Merge pull request #10630 from tschuettler/CRM-CRM-20841
[civicrm-core.git] / CRM / Financial / Form / PaymentEdit.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2018 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2018
32 */
33 class CRM_Financial_Form_PaymentEdit extends CRM_Core_Form {
34
35 /**
36 * The id of the financial trxn.
37 *
38 * @var int
39 */
40 protected $_id;
41
42 /**
43 * The id of the related contribution ID
44 *
45 * @var int
46 */
47 protected $_contributionID;
48
49 /**
50 * The variable which holds the information of a financial transaction
51 *
52 * @var array
53 */
54 protected $_values;
55
56 /**
57 * Explicitly declare the form context.
58 */
59 public function getDefaultContext() {
60 return 'create';
61 }
62 /**
63 * Set variables up before form is built.
64 */
65 public function preProcess() {
66 $this->_action = CRM_Core_Action::UPDATE;
67 parent::preProcess();
68 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
69 $this->assign('id', $this->_id);
70 $this->_contributionID = CRM_Utils_Request::retrieve('contribution_id', 'Positive', $this);
71
72 $this->_values = civicrm_api3('FinancialTrxn', 'getsingle', array('id' => $this->_id));
73 if (!empty($this->_values['payment_processor_id'])) {
74 CRM_Core_Error::statusBounce(ts('You cannot update this payment as it is tied to a payment processor'));
75 }
76 }
77
78 /**
79 * Set default values.
80 *
81 * @return array
82 */
83 public function setDefaultValues() {
84 return $this->_values;
85 }
86
87 /**
88 * Build quickForm.
89 */
90 public function buildQuickForm() {
91 CRM_Utils_System::setTitle(ts('Update Payment details'));
92
93 $paymentFields = $this->getPaymentFields();
94 $this->assign('paymentFields', $paymentFields);
95 foreach ($paymentFields as $name => $paymentField) {
96 if (!empty($paymentField['add_field'])) {
97 $attributes = array(
98 'entity' => 'FinancialTrxn',
99 'name' => $name,
100 );
101 $this->addField($name, $attributes, $paymentField['is_required']);
102 }
103 else {
104 $this->add($paymentField['htmlType'],
105 $name,
106 $paymentField['title'],
107 $paymentField['attributes'],
108 $paymentField['is_required']
109 );
110 }
111 }
112
113 $this->assign('currency', CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_Currency', $this->_values['currency'], 'symbol', 'name'));
114 $this->addFormRule(array(__CLASS__, 'formRule'), $this);
115
116 $this->addButtons(array(
117 array(
118 'type' => 'submit',
119 'name' => ts('Update'),
120 'isDefault' => TRUE,
121 ),
122 array(
123 'type' => 'cancel',
124 'name' => ts('Cancel'),
125 ),
126 ));
127 }
128
129 /**
130 * Global form rule.
131 *
132 * @param array $fields
133 * The input form values.
134 * @param array $files
135 * The uploaded files if any.
136 * @param $self
137 *
138 * @return bool|array
139 * true if no errors, else array of errors
140 */
141 public static function formRule($fields, $files, $self) {
142 $errors = array();
143
144 // if Credit Card is chosen and pan_truncation is not NULL ensure that it's value is numeric else throw validation error
145 if (CRM_Core_PseudoConstant::getName('CRM_Financial_DAO_FinancialTrxn', 'payment_instrument_id', $fields['payment_instrument_id']) == 'Credit Card' &&
146 !empty($fields['pan_truncation']) &&
147 !CRM_Utils_Rule::numeric($fields['pan_truncation'])
148 ) {
149 $errors['pan_truncation'] = ts('Please enter a valid Card Number');
150 }
151
152 return $errors;
153 }
154
155 /**
156 * Process the form submission.
157 */
158 public function postProcess() {
159 $params = array(
160 'id' => $this->_id,
161 'payment_instrument_id' => $this->_submitValues['payment_instrument_id'],
162 'trxn_id' => CRM_Utils_Array::value('trxn_id', $this->_submitValues),
163 'trxn_date' => CRM_Utils_Array::value('trxn_date', $this->_submitValues, date('YmdHis')),
164 );
165
166 $paymentInstrumentName = CRM_Core_PseudoConstant::getName('CRM_Financial_DAO_FinancialTrxn', 'payment_instrument_id', $params['payment_instrument_id']);
167 if ($paymentInstrumentName == 'Credit Card') {
168 $params['card_type_id'] = CRM_Utils_Array::value('card_type_id', $this->_submitValues);
169 $params['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $this->_submitValues);
170 }
171 elseif ($paymentInstrumentName == 'Check') {
172 $params['check_number'] = CRM_Utils_Array::value('check_number', $this->_submitValues);
173 }
174
175 $this->submit($params);
176
177 CRM_Core_Session::singleton()->pushUserContext(CRM_Utils_System::url(CRM_Utils_System::currentPath()));
178 }
179
180 /**
181 * Wrapper function to process form submission
182 *
183 * @param array $submittedValues
184 *
185 */
186 protected function submit($submittedValues) {
187 // if payment instrument is changed then
188 // 1. Record a new reverse financial transaction with old payment instrument
189 // 2. Record a new financial transaction with new payment instrument
190 // 3. Add EntityFinancialTrxn records to relate with corresponding financial item and contribution
191 if ($submittedValues['payment_instrument_id'] != $this->_values['payment_instrument_id']) {
192 $previousFinanciaTrxn = $this->_values;
193 $newFinancialTrxn = $submittedValues;
194 unset($previousFinanciaTrxn['id'], $newFinancialTrxn['id']);
195 $previousFinanciaTrxn['trxn_date'] = CRM_Utils_Array::value('trxn_date', $submittedValues, date('YmdHis'));
196 $previousFinanciaTrxn['total_amount'] = -$previousFinanciaTrxn['total_amount'];
197 $previousFinanciaTrxn['net_amount'] = -$previousFinanciaTrxn['net_amount'];
198 $previousFinanciaTrxn['fee_amount'] = -$previousFinanciaTrxn['fee_amount'];
199 $previousFinanciaTrxn['contribution_id'] = $newFinancialTrxn['contribution_id'] = $this->_contributionID;
200
201 $newFinancialTrxn['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($submittedValues['payment_instrument_id']);
202 foreach (array('total_amount', 'fee_amount', 'net_amount', 'currency', 'is_payment', 'status_id') as $fieldName) {
203 $newFinancialTrxn[$fieldName] = $this->_values[$fieldName];
204 }
205
206 foreach (array($previousFinanciaTrxn, $newFinancialTrxn) as $financialTrxnParams) {
207 civicrm_api3('FinancialTrxn', 'create', $financialTrxnParams);
208 $trxnParams = array(
209 'total_amount' => $financialTrxnParams['total_amount'],
210 'contribution_id' => $this->_contributionID,
211 );
212 $contributionTotalAmount = CRM_Core_DAO::getFieldValue('CRM_Contribute_BAO_Contribution', $this->_contributionID, 'total_amount');
213 CRM_Contribute_BAO_Contribution::assignProportionalLineItems($trxnParams, $submittedValues['id'], $contributionTotalAmount);
214 }
215 }
216 else {
217 // simply update the financial trxn
218 civicrm_api3('FinancialTrxn', 'create', $submittedValues);
219 }
220
221 self::updateRelatedContribution($submittedValues, $this->_contributionID);
222 }
223
224 /**
225 * Wrapper for unit testing the post process submit function.
226 *
227 * @param array $params
228 */
229 public function testSubmit($params) {
230 $this->_id = $params['id'];
231 $this->_contributionID = $params['contribution_id'];
232 $this->_values = civicrm_api3('FinancialTrxn', 'getsingle', array('id' => $params['id']));
233
234 $this->submit($params);
235 }
236
237 /**
238 * Function to update contribution's check_number and trxn_id by
239 * concatenating values from financial trxn's check_number and trxn_id respectively
240 *
241 * @param array $params
242 * @param int $contributionID
243 */
244 public static function updateRelatedContribution($params, $contributionID) {
245 $contributionDAO = new CRM_Contribute_DAO_Contribution();
246 $contributionDAO->id = $contributionID;
247 $contributionDAO->find(TRUE);
248
249 foreach (array('trxn_id', 'check_number') as $fieldName) {
250 if (!empty($params[$fieldName])) {
251 if (!empty($contributionDAO->$fieldName)) {
252 $values = explode(',', $contributionDAO->$fieldName);
253 // if submitted check_number or trxn_id value is
254 // already present then ignore else add to $values array
255 if (!in_array($params[$fieldName], $values)) {
256 $values[] = $params[$fieldName];
257 }
258 $contributionDAO->$fieldName = implode(',', $values);
259 }
260 }
261 }
262
263 $contributionDAO->save();
264 }
265
266 /**
267 * Get payment fields
268 */
269 public function getPaymentFields() {
270 $paymentFields = array(
271 'payment_instrument_id' => array(
272 'is_required' => TRUE,
273 'add_field' => TRUE,
274 ),
275 'check_number' => array(
276 'is_required' => FALSE,
277 'add_field' => TRUE,
278 ),
279 // @TODO we need to show card type icon in place of select field
280 'card_type_id' => array(
281 'is_required' => FALSE,
282 'add_field' => TRUE,
283 ),
284 'pan_truncation' => array(
285 'is_required' => FALSE,
286 'add_field' => TRUE,
287 ),
288 'trxn_id' => array(
289 'add_field' => TRUE,
290 'is_required' => FALSE,
291 ),
292 'trxn_date' => array(
293 'htmlType' => 'datepicker',
294 'name' => 'trxn_date',
295 'title' => ts('Transaction Date'),
296 'is_required' => TRUE,
297 'attributes' => array(
298 'date' => 'yyyy-mm-dd',
299 'time' => 24,
300 ),
301 ),
302 'total_amount' => array(
303 'htmlType' => 'text',
304 'name' => 'total_amount',
305 'title' => ts('Total Amount'),
306 'is_required' => TRUE,
307 'attributes' => array(
308 'readonly' => TRUE,
309 'size' => 6,
310 ),
311 ),
312 );
313
314 return $paymentFields;
315 }
316
317 }