Merge pull request #14658 from MegaphoneJon/mail-46
[civicrm-core.git] / CRM / Financial / BAO / Payment.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
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-2019
32 */
33
34 /**
35 * This class contains payment related functions.
36 */
37 class CRM_Financial_BAO_Payment {
38
39 /**
40 * Function to process additional payment for partial and refund contributions.
41 *
42 * This function is called via API payment.create function. All forms that add payments
43 * should use this.
44 *
45 * @param array $params
46 * - contribution_id
47 * - total_amount
48 * - line_item
49 *
50 * @return \CRM_Financial_DAO_FinancialTrxn
51 *
52 * @throws \API_Exception
53 * @throws \CRM_Core_Exception
54 * @throws \CiviCRM_API3_Exception
55 */
56 public static function create($params) {
57 $contribution = civicrm_api3('Contribution', 'getsingle', ['id' => $params['contribution_id']]);
58 $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus($contribution['contribution_status_id'], 'name');
59
60 $isPaymentCompletesContribution = self::isPaymentCompletesContribution($params['contribution_id'], $params['total_amount']);
61
62 // For legacy reasons Pending payments are completed through completetransaction.
63 // @todo completetransaction should transition components but financial transactions
64 // should be handled through Payment.create.
65 $isSkipRecordingPaymentHereForLegacyHandlingReasons = ($contributionStatus == 'Pending' && $isPaymentCompletesContribution);
66
67 if (!$isSkipRecordingPaymentHereForLegacyHandlingReasons && $params['total_amount'] > 0) {
68 $balanceTrxnParams['to_financial_account_id'] = CRM_Contribute_BAO_Contribution::getToFinancialAccount($contribution, $params);
69 $balanceTrxnParams['from_financial_account_id'] = CRM_Financial_BAO_FinancialAccount::getFinancialAccountForFinancialTypeByRelationship($contribution['financial_type_id'], 'Accounts Receivable Account is');
70 $balanceTrxnParams['total_amount'] = $params['total_amount'];
71 $balanceTrxnParams['contribution_id'] = $params['contribution_id'];
72 $balanceTrxnParams['trxn_date'] = CRM_Utils_Array::value('trxn_date', $params, CRM_Utils_Array::value('contribution_receive_date', $params, date('YmdHis')));
73 $balanceTrxnParams['fee_amount'] = CRM_Utils_Array::value('fee_amount', $params);
74 $balanceTrxnParams['net_amount'] = CRM_Utils_Array::value('total_amount', $params);
75 $balanceTrxnParams['currency'] = $contribution['currency'];
76 $balanceTrxnParams['trxn_id'] = CRM_Utils_Array::value('contribution_trxn_id', $params, NULL);
77 $balanceTrxnParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'status_id', 'Completed');
78 $balanceTrxnParams['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $params, $contribution['payment_instrument_id']);
79 $balanceTrxnParams['check_number'] = CRM_Utils_Array::value('check_number', $params);
80 $balanceTrxnParams['is_payment'] = 1;
81
82 if (!empty($params['payment_processor'])) {
83 // I can't find evidence this is passed in - I was gonna just remove it but decided to deprecate as I see getToFinancialAccount
84 // also anticipates it.
85 CRM_Core_Error::deprecatedFunctionWarning('passing payment_processor is deprecated - use payment_processor_id');
86 $balanceTrxnParams['payment_processor_id'] = $params['payment_processor'];
87 }
88 $trxn = CRM_Core_BAO_FinancialTrxn::create($balanceTrxnParams);
89
90 // @todo - this is just weird & historical & inconsistent - why 2 tracks?
91 if (CRM_Utils_Array::value('line_item', $params) && !empty($trxn)) {
92 foreach ($params['line_item'] as $values) {
93 foreach ($values as $id => $amount) {
94 $p = ['id' => $id];
95 $check = CRM_Price_BAO_LineItem::retrieve($p, $defaults);
96 if (empty($check)) {
97 throw new API_Exception('Please specify a valid Line Item.');
98 }
99 // get financial item
100 $sql = "SELECT fi.id
101 FROM civicrm_financial_item fi
102 INNER JOIN civicrm_line_item li ON li.id = fi.entity_id and fi.entity_table = 'civicrm_line_item'
103 WHERE li.contribution_id = %1 AND li.id = %2";
104 $sqlParams = [
105 1 => [$params['contribution_id'], 'Integer'],
106 2 => [$id, 'Integer'],
107 ];
108 $fid = CRM_Core_DAO::singleValueQuery($sql, $sqlParams);
109 // Record Entity Financial Trxn
110 $eftParams = [
111 'entity_table' => 'civicrm_financial_item',
112 'financial_trxn_id' => $trxn->id,
113 'amount' => $amount,
114 'entity_id' => $fid,
115 ];
116 civicrm_api3('EntityFinancialTrxn', 'create', $eftParams);
117 }
118 }
119 }
120 elseif (!empty($trxn)) {
121 $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($params['contribution_id']);
122 if (!empty($lineItems)) {
123 // get financial item
124 list($ftIds, $taxItems) = CRM_Contribute_BAO_Contribution::getLastFinancialItemIds($params['contribution_id']);
125 $entityParams = [
126 'contribution_total_amount' => $contribution['total_amount'],
127 'trxn_total_amount' => $params['total_amount'],
128 'trxn_id' => $trxn->id,
129 ];
130 $eftParams = [
131 'entity_table' => 'civicrm_financial_item',
132 'financial_trxn_id' => $entityParams['trxn_id'],
133 ];
134 foreach ($lineItems as $key => $value) {
135 if ($value['qty'] == 0) {
136 continue;
137 }
138 $eftParams['entity_id'] = $ftIds[$value['price_field_value_id']];
139 $entityParams['line_item_amount'] = $value['line_total'];
140 CRM_Contribute_BAO_Contribution::createProportionalEntry($entityParams, $eftParams);
141 if (array_key_exists($value['price_field_value_id'], $taxItems)) {
142 $entityParams['line_item_amount'] = $taxItems[$value['price_field_value_id']]['amount'];
143 $eftParams['entity_id'] = $taxItems[$value['price_field_value_id']]['financial_item_id'];
144 CRM_Contribute_BAO_Contribution::createProportionalEntry($entityParams, $eftParams);
145 }
146 }
147 }
148 }
149 }
150 elseif ($params['total_amount'] < 0) {
151 $trxn = self::recordRefundPayment($params['contribution_id'], $params, FALSE);
152 }
153
154 if ($isPaymentCompletesContribution) {
155 if ($contributionStatus == 'Pending refund') {
156 // Ideally we could still call completetransaction as non-payment related actions should
157 // be outside this class. However, for now we just update the contribution here.
158 // Unit test cover in CRM_Event_BAO_AdditionalPaymentTest::testTransactionInfo.
159 civicrm_api3('Contribution', 'create',
160 [
161 'id' => $contribution['id'],
162 'contribution_status_id' => 'Completed',
163 ]
164 );
165 }
166 else {
167 civicrm_api3('Contribution', 'completetransaction', ['id' => $contribution['id']]);
168 // Get the trxn
169 $trxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
170 $ftParams = ['id' => $trxnId['financialTrxnId']];
171 $trxn = CRM_Core_BAO_FinancialTrxn::retrieve($ftParams);
172 }
173 }
174 elseif ($contributionStatus === 'Pending') {
175 civicrm_api3('Contribution', 'create',
176 [
177 'id' => $contribution['id'],
178 'contribution_status_id' => 'Partially paid',
179 ]
180 );
181 }
182 CRM_Contribute_BAO_Contribution::recordPaymentActivity($params['contribution_id'], CRM_Utils_Array::value('participant_id', $params), $params['total_amount'], $trxn->currency, $trxn->trxn_date);
183 return $trxn;
184 }
185
186 /**
187 * Send an email confirming a payment that has been received.
188 *
189 * @param array $params
190 *
191 * @return array
192 */
193 public static function sendConfirmation($params) {
194
195 $entities = self::loadRelatedEntities($params['id']);
196 $sendTemplateParams = [
197 'groupName' => 'msg_tpl_workflow_contribution',
198 'valueName' => 'payment_or_refund_notification',
199 'PDFFilename' => ts('notification') . '.pdf',
200 'contactId' => $entities['contact']['id'],
201 'toName' => $entities['contact']['display_name'],
202 'toEmail' => $entities['contact']['email'],
203 'tplParams' => self::getConfirmationTemplateParameters($entities),
204 ];
205 return CRM_Core_BAO_MessageTemplate::sendTemplate($sendTemplateParams);
206 }
207
208 /**
209 * Load entities related to the current payment id.
210 *
211 * This gives us all the data we need to send an email confirmation but avoiding
212 * getting anything not tested for the confirmations. We retrieve the 'full' event as
213 * it has been traditionally assigned in full.
214 *
215 * @param int $id
216 *
217 * @return array
218 * - contact = ['id' => x, 'display_name' => y, 'email' => z]
219 * - event = [.... full event details......]
220 * - contribution = ['id' => x],
221 * - payment = [payment info + payment summary info]
222 */
223 protected static function loadRelatedEntities($id) {
224 $entities = [];
225 $contributionID = (int) civicrm_api3('EntityFinancialTrxn', 'getvalue', [
226 'financial_trxn_id' => $id,
227 'entity_table' => 'civicrm_contribution',
228 'return' => 'entity_id',
229 ]);
230 $entities['contribution'] = ['id' => $contributionID];
231 $entities['payment'] = array_merge(civicrm_api3('FinancialTrxn', 'getsingle', ['id' => $id]),
232 CRM_Contribute_BAO_Contribution::getPaymentInfo($contributionID)
233 );
234
235 $contactID = self::getPaymentContactID($contributionID);
236 list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID);
237 $entities['contact'] = ['id' => $contactID, 'display_name' => $displayName, 'email' => $email];
238 $contact = civicrm_api3('Contact', 'getsingle', ['id' => $contactID, 'return' => 'email_greeting']);
239 $entities['contact']['email_greeting'] = $contact['email_greeting_display'];
240
241 $participantRecords = civicrm_api3('ParticipantPayment', 'get', [
242 'contribution_id' => $contributionID,
243 'api.Participant.get' => ['return' => 'event_id'],
244 'sequential' => 1,
245 ])['values'];
246 if (!empty($participantRecords)) {
247 $entities['event'] = civicrm_api3('Event', 'getsingle', ['id' => $participantRecords[0]['api.Participant.get']['values'][0]['event_id']]);
248 if (!empty($entities['event']['is_show_location'])) {
249 $locationParams = [
250 'entity_id' => $entities['event']['id'],
251 'entity_table' => 'civicrm_event',
252 ];
253 $entities['location'] = CRM_Core_BAO_Location::getValues($locationParams, TRUE);
254 }
255 }
256
257 return $entities;
258 }
259
260 /**
261 * @param int $contributionID
262 *
263 * @return int
264 */
265 public static function getPaymentContactID($contributionID) {
266 $contribution = civicrm_api3('Contribution', 'getsingle', [
267 'id' => $contributionID ,
268 'return' => ['contact_id'],
269 ]);
270 return (int) $contribution['contact_id'];
271 }
272
273 /**
274 * @param array $entities
275 * Related entities as an array keyed by the various entities.
276 *
277 * @return array
278 * Values required for the notification
279 * - contact_id
280 * - template_variables
281 * - event (DAO of event if relevant)
282 */
283 public static function getConfirmationTemplateParameters($entities) {
284 $templateVariables = [
285 'contactDisplayName' => $entities['contact']['display_name'],
286 'emailGreeting' => $entities['contact']['email_greeting'],
287 'totalAmount' => $entities['payment']['total'],
288 'amountOwed' => $entities['payment']['balance'],
289 'totalPaid' => $entities['payment']['paid'],
290 'paymentAmount' => $entities['payment']['total_amount'],
291 'checkNumber' => CRM_Utils_Array::value('check_number', $entities['payment']),
292 'receive_date' => $entities['payment']['trxn_date'],
293 'paidBy' => CRM_Core_PseudoConstant::getLabel('CRM_Core_BAO_FinancialTrxn', 'payment_instrument_id', $entities['payment']['payment_instrument_id']),
294 'isShowLocation' => (!empty($entities['event']) ? $entities['event']['is_show_location'] : FALSE),
295 'location' => CRM_Utils_Array::value('location', $entities),
296 'event' => CRM_Utils_Array::value('event', $entities),
297 'component' => (!empty($entities['event']) ? 'event' : 'contribution'),
298 'isRefund' => $entities['payment']['total_amount'] < 0,
299 'isAmountzero' => $entities['payment']['total_amount'] === 0,
300 'refundAmount' => ($entities['payment']['total_amount'] < 0 ? $entities['payment']['total_amount'] : NULL),
301 'paymentsComplete' => ($entities['payment']['balance'] == 0),
302 ];
303
304 return self::filterUntestedTemplateVariables($templateVariables);
305 }
306
307 /**
308 * Filter out any untested variables.
309 *
310 * This just serves to highlight if any variables are added without a unit test also being added.
311 *
312 * (if hit then add a unit test for the param & add to this array).
313 *
314 * @param array $params
315 *
316 * @return array
317 */
318 public static function filterUntestedTemplateVariables($params) {
319 $testedTemplateVariables = [
320 'contactDisplayName',
321 'totalAmount',
322 'amountOwed',
323 'paymentAmount',
324 'event',
325 'component',
326 'checkNumber',
327 'receive_date',
328 'paidBy',
329 'isShowLocation',
330 'location',
331 'isRefund',
332 'isAmountzero',
333 'refundAmount',
334 'totalPaid',
335 'paymentsComplete',
336 'emailGreeting',
337 ];
338 // These are assigned by the payment form - they still 'get through' from the
339 // form for now without being in here but we should ideally load
340 // and assign. Note we should update the tpl to use {if $billingName}
341 // and ditch contributeMode - although it might need to be deprecated rather than removed.
342 $todoParams = [
343 'contributeMode',
344 'billingName',
345 'address',
346 'credit_card_type',
347 'credit_card_number',
348 'credit_card_exp_date',
349 ];
350 $filteredParams = [];
351 foreach ($testedTemplateVariables as $templateVariable) {
352 // This will cause an a-notice if any are NOT set - by design. Ensuring
353 // they are set prevents leakage.
354 $filteredParams[$templateVariable] = $params[$templateVariable];
355 }
356 return $filteredParams;
357 }
358
359 /**
360 * @param $contributionId
361 * @param $trxnData
362 * @param $updateStatus
363 * - deprecate this param
364 *
365 * @todo - make this protected once recordAdditionalPayment no longer calls it.
366 *
367 * @return CRM_Financial_DAO_FinancialTrxn
368 */
369 protected static function recordRefundPayment($contributionId, $trxnData, $updateStatus) {
370 list($contributionDAO, $params) = self::getContributionAndParamsInFormatForRecordFinancialTransaction($contributionId);
371
372 $params['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $trxnData, CRM_Utils_Array::value('payment_instrument_id', $params));
373
374 $paidStatus = CRM_Core_PseudoConstant::getKey('CRM_Financial_DAO_FinancialItem', 'status_id', 'Paid');
375 $arAccountId = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contributionDAO->financial_type_id, 'Accounts Receivable Account is');
376 $completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
377
378 $trxnData['total_amount'] = $trxnData['net_amount'] = $trxnData['total_amount'];
379 $trxnData['from_financial_account_id'] = $arAccountId;
380 $trxnData['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Refunded');
381 // record the entry
382 $financialTrxn = CRM_Contribute_BAO_Contribution::recordFinancialAccounts($params, $trxnData);
383
384 // note : not using the self::add method,
385 // the reason because it performs 'status change' related code execution for financial records
386 // which in 'Pending Refund' => 'Completed' is not useful, instead specific financial record updates
387 // are coded below i.e. just updating financial_item status to 'Paid'
388 if ($updateStatus) {
389 CRM_Core_DAO::setFieldValue('CRM_Contribute_BAO_Contribution', $contributionId, 'contribution_status_id', $completedStatusId);
390 }
391 // add financial item entry
392 $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($contributionDAO->id);
393 if (!empty($lineItems)) {
394 foreach ($lineItems as $lineItemId => $lineItemValue) {
395 // don't record financial item for cancelled line-item
396 if ($lineItemValue['qty'] == 0) {
397 continue;
398 }
399 $paid = $financialTrxn->total_amount;
400 if (!empty(floatval($contributionDAO->total_amount))) {
401 $paid = $lineItemValue['line_total'] * ($financialTrxn->total_amount / $contributionDAO->total_amount);
402 }
403 $addFinancialEntry = [
404 'transaction_date' => $financialTrxn->trxn_date,
405 'contact_id' => $contributionDAO->contact_id,
406 'amount' => round($paid, 2),
407 'currency' => $contributionDAO->currency,
408 'status_id' => $paidStatus,
409 'entity_id' => $lineItemId,
410 'entity_table' => 'civicrm_line_item',
411 ];
412 $trxnIds = ['id' => $financialTrxn->id];
413 CRM_Financial_BAO_FinancialItem::create($addFinancialEntry, NULL, $trxnIds);
414 }
415 }
416 return $financialTrxn;
417 }
418
419 /**
420 * @param int $contributionId
421 * @param array $trxnData
422 * @param int $participantId
423 *
424 * @return \CRM_Core_BAO_FinancialTrxn
425 */
426 public static function recordPayment($contributionId, $trxnData, $participantId) {
427 list($contributionDAO, $params) = self::getContributionAndParamsInFormatForRecordFinancialTransaction($contributionId);
428
429 $trxnData['trxn_date'] = !empty($trxnData['trxn_date']) ? $trxnData['trxn_date'] : date('YmdHis');
430 $params['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $trxnData, CRM_Utils_Array::value('payment_instrument_id', $params));
431
432 $paidStatus = CRM_Core_PseudoConstant::getKey('CRM_Financial_DAO_FinancialItem', 'status_id', 'Paid');
433 $arAccountId = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contributionDAO->financial_type_id, 'Accounts Receivable Account is');
434 $completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
435
436 $params['partial_payment_total'] = $contributionDAO->total_amount;
437 $params['partial_amount_to_pay'] = $trxnData['total_amount'];
438 $trxnData['net_amount'] = !empty($trxnData['net_amount']) ? $trxnData['net_amount'] : $trxnData['total_amount'];
439 $params['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $trxnData);
440 $params['card_type_id'] = CRM_Utils_Array::value('card_type_id', $trxnData);
441 $params['check_number'] = CRM_Utils_Array::value('check_number', $trxnData);
442
443 // record the entry
444 $financialTrxn = CRM_Contribute_BAO_Contribution::recordFinancialAccounts($params, $trxnData);
445 $toFinancialAccount = $arAccountId;
446 $trxnId = CRM_Core_BAO_FinancialTrxn::getBalanceTrxnAmt($contributionId, $contributionDAO->financial_type_id);
447 if (!empty($trxnId)) {
448 $trxnId = $trxnId['trxn_id'];
449 }
450 elseif (!empty($contributionDAO->payment_instrument_id)) {
451 $trxnId = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($contributionDAO->payment_instrument_id);
452 }
453 else {
454 $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('financial_account_type', NULL, " AND v.name LIKE 'Asset' "));
455 $queryParams = [1 => [$relationTypeId, 'Integer']];
456 $trxnId = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_financial_account WHERE is_default = 1 AND financial_account_type_id = %1", $queryParams);
457 }
458
459 // update statuses
460 // criteria for updates contribution total_amount == financial_trxns of partial_payments
461 $sql = "SELECT SUM(ft.total_amount) as sum_of_payments, SUM(ft.net_amount) as net_amount_total
462 FROM civicrm_financial_trxn ft
463 LEFT JOIN civicrm_entity_financial_trxn eft
464 ON (ft.id = eft.financial_trxn_id)
465 WHERE eft.entity_table = 'civicrm_contribution'
466 AND eft.entity_id = {$contributionId}
467 AND ft.to_financial_account_id != {$toFinancialAccount}
468 AND ft.status_id = {$completedStatusId}
469 ";
470 $query = CRM_Core_DAO::executeQuery($sql);
471 $query->fetch();
472 $sumOfPayments = $query->sum_of_payments;
473
474 // update statuses
475 if ($contributionDAO->total_amount == $sumOfPayments) {
476 // update contribution status and
477 // clean cancel info (if any) if prev. contribution was updated in case of 'Refunded' => 'Completed'
478 $contributionDAO->contribution_status_id = $completedStatusId;
479 $contributionDAO->cancel_date = 'null';
480 $contributionDAO->cancel_reason = NULL;
481 $netAmount = !empty($trxnData['net_amount']) ? NULL : $trxnData['total_amount'];
482 $contributionDAO->net_amount = $query->net_amount_total + $netAmount;
483 $contributionDAO->fee_amount = $contributionDAO->total_amount - $contributionDAO->net_amount;
484 $contributionDAO->save();
485
486 //Change status of financial record too
487 $financialTrxn->status_id = $completedStatusId;
488 $financialTrxn->save();
489
490 // note : not using the self::add method,
491 // the reason because it performs 'status change' related code execution for financial records
492 // which in 'Partial Paid' => 'Completed' is not useful, instead specific financial record updates
493 // are coded below i.e. just updating financial_item status to 'Paid'
494
495 if (!$participantId) {
496 $participantId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $contributionId, 'participant_id', 'contribution_id');
497 }
498 if ($participantId) {
499 // update participant status
500 $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
501 $ids = CRM_Event_BAO_Participant::getParticipantIds($contributionId);
502 foreach ($ids as $val) {
503 $participantUpdate['id'] = $val;
504 $participantUpdate['status_id'] = array_search('Registered', $participantStatuses);
505 CRM_Event_BAO_Participant::add($participantUpdate);
506 }
507 }
508
509 // Remove this - completeOrder does it.
510 CRM_Contribute_BAO_Contribution::updateMembershipBasedOnCompletionOfContribution(
511 $contributionDAO,
512 $contributionId,
513 $trxnData['trxn_date']
514 );
515
516 // update financial item statuses
517 $baseTrxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contributionId);
518 $sqlFinancialItemUpdate = "
519 UPDATE civicrm_financial_item fi
520 LEFT JOIN civicrm_entity_financial_trxn eft
521 ON (eft.entity_id = fi.id AND eft.entity_table = 'civicrm_financial_item')
522 SET status_id = {$paidStatus}
523 WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})
524 ";
525 CRM_Core_DAO::executeQuery($sqlFinancialItemUpdate);
526 }
527 return $financialTrxn;
528 }
529
530 /**
531 * The recordFinancialTransactions function has capricious requirements for input parameters - load them.
532 *
533 * The function needs rework but for now we need to give it what it wants.
534 *
535 * @param int $contributionId
536 *
537 * @return array
538 */
539 protected static function getContributionAndParamsInFormatForRecordFinancialTransaction($contributionId) {
540 $getInfoOf['id'] = $contributionId;
541 $defaults = [];
542 $contributionDAO = CRM_Contribute_BAO_Contribution::retrieve($getInfoOf, $defaults);
543
544 // build params for recording financial trxn entry
545 $params['contribution'] = $contributionDAO;
546 $params = array_merge($defaults, $params);
547 $params['skipLineItem'] = TRUE;
548 return [$contributionDAO, $params];
549 }
550
551 /**
552 * Does this payment complete the contribution
553 *
554 * @param int $contributionID
555 * @param float $paymentAmount
556 *
557 * @return bool
558 */
559 protected static function isPaymentCompletesContribution($contributionID, $paymentAmount) {
560 $outstandingBalance = CRM_Contribute_BAO_Contribution::getContributionBalance($contributionID);
561 $cmp = bccomp($paymentAmount, $outstandingBalance, 5);
562 return ($cmp == 0 || $cmp == 1);
563 }
564
565 }