Merge pull request #18010 from eileenmcnaughton/pex
[civicrm-core.git] / CRM / Contribute / Form / Task / Batch.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * This class provides the functionality for batch profile update for contributions.
20 */
21 class CRM_Contribute_Form_Task_Batch extends CRM_Contribute_Form_Task {
22
23 /**
24 * The title of the group
25 *
26 * @var string
27 */
28 protected $_title;
29
30 /**
31 * Maximum profile fields that will be displayed
32 * @var int
33 */
34 protected $_maxFields = 9;
35
36 /**
37 * Variable to store redirect path
38 * @var string
39 */
40 protected $_userContext;
41
42 /**
43 * Build all the data structures needed to build the form.
44 */
45 public function preProcess() {
46 // initialize the task and row fields
47 parent::preProcess();
48
49 //get the contact read only fields to display.
50 $readOnlyFields = array_merge(['sort_name' => ts('Name')],
51 CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
52 'contact_autocomplete_options',
53 TRUE, NULL, FALSE, 'name', TRUE
54 )
55 );
56 //get the read only field data.
57 $returnProperties = array_fill_keys(array_keys($readOnlyFields), 1);
58 $contactDetails = CRM_Contact_BAO_Contact_Utils::contactDetails($this->_contributionIds,
59 'CiviContribute', $returnProperties
60 );
61 $this->assign('contactDetails', $contactDetails);
62 $this->assign('readOnlyFields', $readOnlyFields);
63 }
64
65 /**
66 * Build the form object.
67 */
68 public function buildQuickForm() {
69 $ufGroupId = $this->get('ufGroupId');
70
71 if (!$ufGroupId) {
72 throw new CRM_Core_Exception('ufGroupId is missing');
73 }
74 $this->_title = ts('Update multiple contributions') . ' - ' . CRM_Core_BAO_UFGroup::getTitle($ufGroupId);
75 CRM_Utils_System::setTitle($this->_title);
76
77 $this->addDefaultButtons(ts('Save'));
78 $this->_fields = [];
79 $this->_fields = CRM_Core_BAO_UFGroup::getFields($ufGroupId, FALSE, CRM_Core_Action::VIEW);
80
81 // remove file type field and then limit fields
82 $suppressFields = FALSE;
83 $removehtmlTypes = ['File'];
84 foreach ($this->_fields as $name => $field) {
85 if ($cfID = CRM_Core_BAO_CustomField::getKeyID($name) &&
86 in_array($this->_fields[$name]['html_type'], $removehtmlTypes)
87 ) {
88 $suppressFields = TRUE;
89 unset($this->_fields[$name]);
90 }
91
92 //fix to reduce size as we are using this field in grid
93 if (is_array($field['attributes']) && !empty($this->_fields[$name]['attributes']['size']) && $this->_fields[$name]['attributes']['size'] > 19) {
94 //shrink class to "form-text-medium"
95 $this->_fields[$name]['attributes']['size'] = 19;
96 }
97 }
98
99 $this->_fields = array_slice($this->_fields, 0, $this->_maxFields);
100
101 $this->addButtons([
102 [
103 'type' => 'submit',
104 'name' => ts('Update Contribution(s)'),
105 'isDefault' => TRUE,
106 ],
107 [
108 'type' => 'cancel',
109 'name' => ts('Cancel'),
110 ],
111 ]);
112
113 $this->assign('profileTitle', $this->_title);
114 $this->assign('componentIds', $this->_contributionIds);
115
116 //load all campaigns.
117 if (array_key_exists('contribution_campaign_id', $this->_fields)) {
118 $this->_componentCampaigns = [];
119 CRM_Core_PseudoConstant::populate($this->_componentCampaigns,
120 'CRM_Contribute_DAO_Contribution',
121 TRUE, 'campaign_id', 'id',
122 ' id IN (' . implode(' , ', array_values($this->_contributionIds)) . ' ) '
123 );
124 }
125
126 // It is possible to have fields that are required in CiviCRM not be required in the
127 // profile. Overriding that here. Perhaps a better approach would be to
128 // make them required in the schema & read that up through getFields functionality.
129 $requiredFields = ['receive_date'];
130
131 //fix for CRM-2752
132 $customFields = CRM_Core_BAO_CustomField::getFields('Contribution');
133 foreach ($this->_contributionIds as $contributionId) {
134 $typeId = CRM_Core_DAO::getFieldValue("CRM_Contribute_DAO_Contribution", $contributionId, 'financial_type_id');
135 foreach ($this->_fields as $name => $field) {
136 $entityColumnValue = [];
137 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
138 $customValue = $customFields[$customFieldID] ?? NULL;
139 if (!empty($customValue['extends_entity_column_value'])) {
140 $entityColumnValue = explode(CRM_Core_DAO::VALUE_SEPARATOR,
141 $customValue['extends_entity_column_value']
142 );
143 }
144
145 if (!empty($entityColumnValue[$typeId]) ||
146 CRM_Utils_System::isNull(CRM_Utils_Array::value($typeId, $entityColumnValue))
147 ) {
148 CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contributionId);
149 }
150 }
151 else {
152 // handle non custom fields
153 if (in_array($field['name'], $requiredFields)) {
154 $field['is_required'] = TRUE;
155 }
156 CRM_Core_BAO_UFGroup::buildProfile($this, $field, NULL, $contributionId);
157 }
158 }
159 }
160
161 $this->assign('fields', $this->_fields);
162
163 // don't set the status message when form is submitted.
164 $buttonName = $this->controller->getButtonName('submit');
165
166 if ($suppressFields && $buttonName != '_qf_Batch_next') {
167 CRM_Core_Session::setStatus(ts("File type field(s) in the selected profile are not supported for Update multiple contributions."), ts('Unsupported Field Type'), 'error');
168 }
169
170 $this->addDefaultButtons(ts('Update Contributions'));
171 }
172
173 /**
174 * Set default values for the form.
175 */
176 public function setDefaultValues() {
177 if (empty($this->_fields)) {
178 return;
179 }
180
181 $defaults = [];
182 foreach ($this->_contributionIds as $contributionId) {
183 CRM_Core_BAO_UFGroup::setProfileDefaults(NULL, $this->_fields, $defaults, FALSE, $contributionId, 'Contribute');
184 }
185
186 return $defaults;
187 }
188
189 /**
190 * Process the form after the input has been submitted and validated.
191 */
192 public function postProcess() {
193 $params = $this->exportValues();
194 // @todo extract submit functions &
195 // extend CRM_Event_Form_Task_BatchTest::testSubmit with a data provider to test
196 // handling of custom data, specifically checkbox fields.
197 if (isset($params['field'])) {
198 foreach ($params['field'] as $contributionID => $value) {
199
200 $value['id'] = $contributionID;
201 if (!empty($value['financial_type'])) {
202 $value['financial_type_id'] = $value['financial_type'];
203 }
204
205 $value['options'] = [
206 'reload' => 1,
207 ];
208 $contribution = civicrm_api3('Contribution', 'create', $value);
209 $contribution = $contribution['values'][$contributionID];
210
211 // @todo add check as to whether the status is updated.
212 if (!empty($value['contribution_status_id'])) {
213 // @todo - use completeorder api or make api call do this.
214 CRM_Contribute_BAO_Contribution::transitionComponentWithReturnMessage($contribution['id'],
215 $value['contribution_status_id'],
216 CRM_Utils_Array::value("field[{$contributionID}][contribution_status_id]", $this->_defaultValues),
217 $contribution['receive_date']
218 );
219 }
220 }
221 CRM_Core_Session::setStatus(ts("Your updates have been saved."), ts('Saved'), 'success');
222 }
223 else {
224 CRM_Core_Session::setStatus(ts("No updates have been saved."), ts('Not Saved'), 'alert');
225 }
226 }
227
228 }