Revert "Schema - Fix boolean fields in various tables"
[civicrm-core.git] / CRM / Financial / Form / PaymentEdit.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 class CRM_Financial_Form_PaymentEdit extends CRM_Core_Form {
18
19 /**
20 * Should financials be checked after the test but before tear down.
21 *
22 * Ideally all tests (or at least all that call any financial api calls ) should do this but there
23 * are some test data issues and some real bugs currently blocking.
24 *
25 * @var bool
26 */
27 protected $isValidateFinancialsOnPostAssert = TRUE;
28
29 /**
30 * The id of the financial trxn.
31 *
32 * @var int
33 */
34 protected $_id;
35
36 /**
37 * The id of the related contribution ID
38 *
39 * @var int
40 */
41 protected $_contributionID;
42
43 /**
44 * Get the related contribution id.
45 *
46 * @return int
47 */
48 public function getContributionID(): int {
49 return $this->_contributionID;
50 }
51
52 /**
53 * The variable which holds the information of a financial transaction
54 *
55 * @var array
56 */
57 protected $_values;
58
59 /**
60 * Explicitly declare the form context.
61 */
62 public function getDefaultContext() {
63 return 'create';
64 }
65
66 /**
67 * Set variables up before form is built.
68 */
69 public function preProcess() {
70 $this->_action = CRM_Core_Action::UPDATE;
71 parent::preProcess();
72 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
73 $this->assign('id', $this->_id);
74 $this->_contributionID = CRM_Utils_Request::retrieve('contribution_id', 'Positive', $this);
75
76 $this->_values = civicrm_api3('FinancialTrxn', 'getsingle', ['id' => $this->_id]);
77 if (!empty($this->_values['payment_processor_id'])) {
78 CRM_Core_Error::statusBounce(ts('You cannot update this payment as it is tied to a payment processor'));
79 }
80 }
81
82 /**
83 * Set default values.
84 *
85 * @return array
86 */
87 public function setDefaultValues() {
88 $defaults = $this->_values;
89 $defaults['total_amount'] = CRM_Utils_Money::formatLocaleNumericRoundedForDefaultCurrency($this->_values['total_amount']);
90 return $defaults;
91 }
92
93 /**
94 * Build quickForm.
95 */
96 public function buildQuickForm() {
97 $this->setTitle(ts('Update Payment details'));
98
99 $paymentFields = $this->getPaymentFields();
100 $this->assign('paymentFields', $paymentFields);
101 foreach ($paymentFields as $name => $paymentField) {
102 if (!empty($paymentField['add_field'])) {
103 $attributes = [
104 'entity' => 'FinancialTrxn',
105 'name' => $name,
106 ];
107 $this->addField($name, $attributes, $paymentField['is_required']);
108 }
109 else {
110 $this->add($paymentField['htmlType'],
111 $name,
112 $paymentField['title'],
113 $paymentField['attributes'],
114 $paymentField['is_required']
115 );
116 }
117 }
118
119 $this->assign('currency', CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_Currency', $this->_values['currency'], 'symbol', 'name'));
120 $this->addFormRule([__CLASS__, 'formRule'], $this);
121
122 $this->addButtons([
123 [
124 'type' => 'submit',
125 'name' => ts('Update'),
126 'isDefault' => TRUE,
127 ],
128 [
129 'type' => 'cancel',
130 'name' => ts('Cancel'),
131 ],
132 ]);
133 }
134
135 /**
136 * Global form rule.
137 *
138 * @param array $fields
139 * The input form values.
140 * @param array $files
141 * The uploaded files if any.
142 * @param self $self
143 *
144 * @return bool|array
145 * true if no errors, else array of errors
146 */
147 public static function formRule($fields, $files, $self) {
148 $errors = [];
149
150 // if Credit Card is chosen and pan_truncation is not NULL ensure that it's value is numeric else throw validation error
151 if (CRM_Core_PseudoConstant::getName('CRM_Financial_DAO_FinancialTrxn', 'payment_instrument_id', $fields['payment_instrument_id']) === 'Credit Card' &&
152 !empty($fields['pan_truncation']) &&
153 !CRM_Utils_Rule::numeric($fields['pan_truncation'])
154 ) {
155 $errors['pan_truncation'] = ts('Please enter a valid Card Number');
156 }
157
158 return $errors;
159 }
160
161 /**
162 * Process the form submission.
163 *
164 * @throws \CiviCRM_API3_Exception
165 */
166 public function postProcess(): void {
167 $params = [
168 'id' => $this->_id,
169 'payment_instrument_id' => $this->_submitValues['payment_instrument_id'],
170 'trxn_id' => $this->_submitValues['trxn_id'] ?? NULL,
171 'trxn_date' => CRM_Utils_Array::value('trxn_date', $this->_submitValues, date('YmdHis')),
172 ];
173
174 $paymentInstrumentName = CRM_Core_PseudoConstant::getName('CRM_Financial_DAO_FinancialTrxn', 'payment_instrument_id', $params['payment_instrument_id']);
175 if ($paymentInstrumentName === 'Credit Card') {
176 $params['card_type_id'] = $this->_submitValues['card_type_id'] ?? NULL;
177 $params['pan_truncation'] = $this->_submitValues['pan_truncation'] ?? NULL;
178 }
179 elseif ($paymentInstrumentName === 'Check') {
180 $params['check_number'] = $this->_submitValues['check_number'] ?? NULL;
181 }
182
183 $this->submit($params);
184
185 $contactId = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $this->getContributionID(), 'contact_id');
186 $url = CRM_Utils_System::url(
187 "civicrm/contact/view/contribution",
188 "reset=1&action=update&id=" . $this->getContributionID() . "&cid={$contactId}&context=contribution"
189 );
190 CRM_Core_Session::singleton()->pushUserContext($url);
191 }
192
193 /**
194 * Wrapper function to process form submission
195 *
196 * @param array $submittedValues
197 *
198 * @throws \CiviCRM_API3_Exception
199 */
200 protected function submit($submittedValues) {
201 // if payment instrument is changed then
202 // 1. Record a new reverse financial transaction with old payment instrument
203 // 2. Record a new financial transaction with new payment instrument
204 // 3. Add EntityFinancialTrxn records to relate with corresponding financial item and contribution
205 if ($submittedValues['payment_instrument_id'] != $this->_values['payment_instrument_id']) {
206 civicrm_api3('Payment', 'cancel', [
207 'id' => $this->_values['id'],
208 'trxn_date' => $submittedValues['trxn_date'],
209 ]);
210
211 $newFinancialTrxn = $submittedValues;
212 unset($newFinancialTrxn['id']);
213 $newFinancialTrxn['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($submittedValues['payment_instrument_id']);
214 $newFinancialTrxn['total_amount'] = $this->_values['total_amount'];
215 $newFinancialTrxn['currency'] = $this->_values['currency'];
216 $newFinancialTrxn['contribution_id'] = $this->getContributionID();
217 civicrm_api3('Payment', 'create', $newFinancialTrxn);
218 }
219 else {
220 // simply update the financial trxn
221 civicrm_api3('FinancialTrxn', 'create', $submittedValues);
222 }
223
224 CRM_Financial_BAO_Payment::updateRelatedContribution($submittedValues, $this->getContributionID());
225 }
226
227 /**
228 * Wrapper for unit testing the post process submit function.
229 *
230 * @param array $params
231 *
232 * @throws \CiviCRM_API3_Exception
233 */
234 public function testSubmit(array $params): void {
235 $this->_id = $params['id'];
236 $this->_contributionID = $params['contribution_id'];
237 $this->_values = civicrm_api3('FinancialTrxn', 'getsingle', ['id' => $params['id']]);
238
239 $this->submit($params);
240 }
241
242 /**
243 * Get payment fields
244 */
245 public function getPaymentFields() {
246 $paymentFields = [
247 'payment_instrument_id' => [
248 'is_required' => TRUE,
249 'add_field' => TRUE,
250 ],
251 'check_number' => [
252 'is_required' => FALSE,
253 'add_field' => TRUE,
254 ],
255 // @TODO we need to show card type icon in place of select field
256 'card_type_id' => [
257 'is_required' => FALSE,
258 'add_field' => TRUE,
259 ],
260 'pan_truncation' => [
261 'is_required' => FALSE,
262 'add_field' => TRUE,
263 ],
264 'trxn_id' => [
265 'add_field' => TRUE,
266 'is_required' => FALSE,
267 ],
268 'trxn_date' => [
269 'htmlType' => 'datepicker',
270 'name' => 'trxn_date',
271 'title' => ts('Transaction Date'),
272 'is_required' => TRUE,
273 'attributes' => [
274 'date' => 'yyyy-mm-dd',
275 'time' => 24,
276 ],
277 ],
278 'total_amount' => [
279 'htmlType' => 'text',
280 'name' => 'total_amount',
281 'title' => ts('Total Amount'),
282 'is_required' => TRUE,
283 'attributes' => [
284 'readonly' => TRUE,
285 'size' => 6,
286 ],
287 ],
288 ];
289
290 return $paymentFields;
291 }
292
293 }