3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.7 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2015
35 class CRM_Pledge_BAO_PledgePayment
extends CRM_Pledge_DAO_PledgePayment
{
40 public function __construct() {
41 parent
::__construct();
45 * Get pledge payment details.
47 * @param int $pledgeId
51 * associated array of pledge payment details
53 public static function getPledgePayments($pledgeId) {
55 SELECT civicrm_pledge_payment.id id,
62 civicrm_pledge_payment.currency,
63 civicrm_option_value.name as status,
64 civicrm_option_value.label as label,
65 civicrm_contribution.id as contribution_id
66 FROM civicrm_pledge_payment
68 LEFT JOIN civicrm_contribution ON civicrm_pledge_payment.contribution_id = civicrm_contribution.id
69 LEFT JOIN civicrm_option_group ON ( civicrm_option_group.name = 'contribution_status' )
70 LEFT JOIN civicrm_option_value ON ( civicrm_pledge_payment.status_id = civicrm_option_value.value AND
71 civicrm_option_group.id = civicrm_option_value.option_group_id )
75 $params[1] = array($pledgeId, 'Integer');
76 $payment = CRM_Core_DAO
::executeQuery($query, $params);
78 $paymentDetails = array();
79 while ($payment->fetch()) {
80 $paymentDetails[$payment->id
]['scheduled_amount'] = $payment->scheduled_amount
;
81 $paymentDetails[$payment->id
]['scheduled_date'] = $payment->scheduled_date
;
82 $paymentDetails[$payment->id
]['reminder_date'] = $payment->reminder_date
;
83 $paymentDetails[$payment->id
]['reminder_count'] = $payment->reminder_count
;
84 $paymentDetails[$payment->id
]['total_amount'] = $payment->actual_amount
;
85 $paymentDetails[$payment->id
]['receive_date'] = $payment->receive_date
;
86 $paymentDetails[$payment->id
]['status'] = $payment->status
;
87 $paymentDetails[$payment->id
]['label'] = $payment->label
;
88 $paymentDetails[$payment->id
]['id'] = $payment->id
;
89 $paymentDetails[$payment->id
]['contribution_id'] = $payment->contribution_id
;
90 $paymentDetails[$payment->id
]['currency'] = $payment->currency
;
93 return $paymentDetails;
97 * @param array $params
101 public static function create($params) {
102 $transaction = new CRM_Core_Transaction();
103 $contributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
105 //calculate the scheduled date for every installment
106 $now = date('Ymd') . '000000';
107 $statues = $prevScheduledDate = array();
108 $prevScheduledDate[1] = CRM_Utils_Date
::processDate($params['scheduled_date']);
110 if (CRM_Utils_Date
::overdue($prevScheduledDate[1], $now)) {
111 $statues[1] = array_search('Overdue', $contributionStatus);
114 $statues[1] = array_search('Pending', $contributionStatus);
117 for ($i = 1; $i < $params['installments']; $i++
) {
118 $prevScheduledDate[$i +
1] = self
::calculateNextScheduledDate($params, $i);
119 if (CRM_Utils_Date
::overdue($prevScheduledDate[$i +
1], $now)) {
120 $statues[$i +
1] = array_search('Overdue', $contributionStatus);
123 $statues[$i +
1] = array_search('Pending', $contributionStatus);
127 if ($params['installment_amount']) {
128 $params['scheduled_amount'] = $params['installment_amount'];
131 $params['scheduled_amount'] = round(($params['amount'] / $params['installments']), 2);
134 for ($i = 1; $i <= $params['installments']; $i++
) {
135 //calculate the scheduled amount for every installment.
136 if ($i == $params['installments']) {
137 $params['scheduled_amount'] = $params['amount'] - ($i - 1) * $params['scheduled_amount'];
139 if (!isset($params['contribution_id']) && $params['installments'] > 1) {
140 $params['status_id'] = $statues[$i];
143 $params['scheduled_date'] = $prevScheduledDate[$i];
144 $payment = self
::add($params);
145 if (is_a($payment, 'CRM_Core_Error')) {
146 $transaction->rollback();
150 // we should add contribution id to only first payment record
151 if (isset($params['contribution_id'])) {
152 unset($params['contribution_id']);
153 unset($params['actual_amount']);
157 //update pledge status
158 self
::updatePledgePaymentStatus($params['pledge_id']);
160 $transaction->commit();
165 * Add pledge payment.
167 * @param array $params
168 * Associate array of field.
170 * @return CRM_Pledge_DAO_PledgePayment
173 public static function add($params) {
174 if (!empty($params['id'])) {
175 CRM_Utils_Hook
::pre('edit', 'PledgePayment', $params['id'], $params);
178 CRM_Utils_Hook
::pre('create', 'PledgePayment', NULL, $params);
181 $payment = new CRM_Pledge_DAO_PledgePayment();
182 $payment->copyValues($params);
184 // set currency for CRM-1496
185 if (!isset($payment->currency
)) {
186 $payment->currency
= CRM_Core_Config
::singleton()->defaultCurrency
;
189 $result = $payment->save();
191 if (!empty($params['id'])) {
192 CRM_Utils_Hook
::post('edit', 'PledgePayment', $payment->id
, $payment);
195 CRM_Utils_Hook
::post('create', 'PledgePayment', $payment->id
, $payment);
202 * Retrieve DB object based on input parameters.
204 * It also stores all the retrieved values in the default array.
206 * @param array $params
207 * (reference ) an assoc array of name/value pairs.
208 * @param array $defaults
209 * (reference ) an assoc array to hold the flattened values.
211 * @return CRM_Pledge_BAO_PledgePayment
213 public static function retrieve(&$params, &$defaults) {
214 $payment = new CRM_Pledge_BAO_PledgePayment();
215 $payment->copyValues($params);
216 if ($payment->find(TRUE)) {
217 CRM_Core_DAO
::storeValues($payment, $defaults);
224 * Delete pledge payment.
231 public static function del($id) {
232 $payment = new CRM_Pledge_DAO_PledgePayment();
234 if ($payment->find()) {
237 CRM_Utils_Hook
::pre('delete', 'PledgePayment', $id, $payment);
239 $result = $payment->delete();
241 CRM_Utils_Hook
::post('delete', 'PledgePayment', $id, $payment);
251 * Delete all pledge payments.
258 public static function deletePayments($id) {
259 if (!CRM_Utils_Rule
::positiveInteger($id)) {
263 $transaction = new CRM_Core_Transaction();
265 $payment = new CRM_Pledge_DAO_PledgePayment();
266 $payment->pledge_id
= $id;
268 if ($payment->find()) {
269 while ($payment->fetch()) {
270 //also delete associated contribution.
271 if ($payment->contribution_id
) {
272 CRM_Contribute_BAO_Contribution
::deleteContribution($payment->contribution_id
);
278 $transaction->commit();
284 * On delete contribution record update associated pledge payment and pledge.
286 * @param int $contributionID
291 public static function resetPledgePayment($contributionID) {
293 $allStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
295 $transaction = new CRM_Core_Transaction();
297 $payment = new CRM_Pledge_DAO_PledgePayment();
298 $payment->contribution_id
= $contributionID;
299 if ($payment->find(TRUE)) {
300 $payment->contribution_id
= 'null';
301 $payment->status_id
= array_search('Pending', $allStatus);
302 $payment->scheduled_date
= NULL;
303 $payment->reminder_date
= NULL;
304 $payment->scheduled_amount
= $payment->actual_amount
;
305 $payment->actual_amount
= 'null';
308 //update pledge status.
309 $pledgeID = $payment->pledge_id
;
310 $pledgeStatusID = self
::calculatePledgeStatus($pledgeID);
311 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_Pledge', $pledgeID, 'status_id', $pledgeStatusID);
316 $transaction->commit();
321 * Update Pledge Payment Status.
323 * @param int $pledgeID
325 * @param array $paymentIDs
326 * , ids of pledge payment(s) to update.
327 * @param int $paymentStatusID
328 * , payment status to set.
329 * @param int $pledgeStatusID
330 * Pledge status to change (if needed).
331 * @param float|int $actualAmount , actual amount being paid
332 * @param bool $adjustTotalAmount
333 * , is amount being paid different from scheduled amount?.
334 * @param bool $isScriptUpdate
335 * , is function being called from bin script?.
338 * $newStatus, updated status id (or 0)
340 public static function updatePledgePaymentStatus(
343 $paymentStatusID = NULL,
344 $pledgeStatusID = NULL,
346 $adjustTotalAmount = FALSE,
347 $isScriptUpdate = FALSE
349 $totalAmountClause = '';
350 $paymentContributionId = NULL;
351 $editScheduled = FALSE;
354 $allStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
356 // if we get do not get contribution id means we are editing the scheduled payment.
357 if (!empty($paymentIDs)) {
358 $editScheduled = FALSE;
359 $payments = implode(',', $paymentIDs);
360 $paymentContributionId = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_PledgePayment',
366 if (!$paymentContributionId) {
367 $editScheduled = TRUE;
371 // if payment ids are passed, we update payment table first, since payments statuses are not dependent on pledge status
372 if ((!empty($paymentIDs) ||
$pledgeStatusID == array_search('Cancelled', $allStatus)) && (!$editScheduled ||
$isScriptUpdate)) {
373 if ($pledgeStatusID == array_search('Cancelled', $allStatus)) {
374 $paymentStatusID = $pledgeStatusID;
377 self
::updatePledgePayments($pledgeID, $paymentStatusID, $paymentIDs, $actualAmount, $paymentContributionId, $isScriptUpdate);
379 if (!empty($paymentIDs) && $actualAmount) {
380 $payments = implode(',', $paymentIDs);
381 $pledgeScheduledAmount = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_PledgePayment',
387 $pledgeStatusId = self
::calculatePledgeStatus($pledgeID);
388 // Actual Pledge Amount
389 $actualPledgeAmount = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_Pledge',
394 // while editing scheduled we need to check if we are editing last pending
395 $lastPending = FALSE;
396 if (!$paymentContributionId) {
397 $checkPendingCount = self
::getOldestPledgePayment($pledgeID, 2);
398 if ($checkPendingCount['count'] == 1) {
403 // check if this is the last payment and adjust the actual amount.
404 if ($pledgeStatusId && $pledgeStatusId == array_search('Completed', $allStatus) ||
$lastPending) {
405 // last scheduled payment
406 if ($actualAmount >= $pledgeScheduledAmount) {
407 $adjustTotalAmount = TRUE;
409 elseif (!$adjustTotalAmount) {
410 // actual amount is less than the scheduled amount, so enter new pledge payment record
411 $pledgeFrequencyUnit = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_Pledge', $pledgeID, 'frequency_unit', 'id');
412 $pledgeFrequencyInterval = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_Pledge', $pledgeID, 'frequency_interval', 'id');
413 $pledgeScheduledDate = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_PledgePayment', $payments, 'scheduled_date', 'id');
414 $scheduled_date = CRM_Utils_Date
::processDate($pledgeScheduledDate);
415 $date['year'] = (int) substr($scheduled_date, 0, 4);
416 $date['month'] = (int) substr($scheduled_date, 4, 2);
417 $date['day'] = (int) substr($scheduled_date, 6, 2);
418 $newDate = date('YmdHis', mktime(0, 0, 0, $date['month'], $date['day'], $date['year']));
419 $ScheduledDate = CRM_Utils_Date
::format(CRM_Utils_Date
::intervalAdd($pledgeFrequencyUnit,
420 $pledgeFrequencyInterval, $newDate
422 $pledgeParams = array(
423 'status_id' => array_search('Pending', $allStatus),
424 'pledge_id' => $pledgeID,
425 'scheduled_amount' => ($pledgeScheduledAmount - $actualAmount),
426 'scheduled_date' => $ScheduledDate,
428 $payment = self
::add($pledgeParams);
429 // while editing schedule, after adding a new pledge payemnt update the scheduled amount of the current payment
430 if (!$paymentContributionId) {
431 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment', $payments, 'scheduled_amount', $actualAmount);
435 elseif (!$adjustTotalAmount) {
436 // not last schedule amount and also not selected to adjust Total
437 $paymentContributionId = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_PledgePayment',
442 self
::adjustPledgePayment($pledgeID, $actualAmount, $pledgeScheduledAmount, $paymentContributionId, $payments, $paymentStatusID);
443 // while editing schedule, after adding a new pledge payemnt update the scheduled amount of the current payment
444 if (!$paymentContributionId) {
445 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment', $payments, 'scheduled_amount', $actualAmount);
447 // after adjusting all payments check if the actual amount was greater than the actual remaining amount , if so then update the total pledge amount.
448 $pledgeStatusId = self
::calculatePledgeStatus($pledgeID);
450 SELECT sum( civicrm_pledge_payment.actual_amount )
451 FROM civicrm_pledge_payment
452 WHERE civicrm_pledge_payment.pledge_id = %1
453 AND civicrm_pledge_payment.status_id = 1
455 $totalPaidParams = array(1 => array($pledgeID, 'Integer'));
456 $totalPaidAmount = CRM_Core_DAO
::singleValueQuery($balanceQuery, $totalPaidParams);
457 $remainingTotalAmount = ($actualPledgeAmount - $totalPaidAmount);
458 if (($pledgeStatusId && $pledgeStatusId == array_search('Completed', $allStatus)) && (($actualAmount > $remainingTotalAmount) ||
($actualAmount >= $actualPledgeAmount))) {
459 $totalAmountClause = ", civicrm_pledge.amount = {$totalPaidAmount}";
462 if ($adjustTotalAmount) {
463 $newTotalAmount = ($actualPledgeAmount +
($actualAmount - $pledgeScheduledAmount));
464 $totalAmountClause = ", civicrm_pledge.amount = {$newTotalAmount}";
465 if (!$paymentContributionId) {
466 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment', $payments, 'scheduled_amount', $actualAmount);
471 $cancelDateClause = $endDateClause = NULL;
472 //update pledge and payment status if status is Completed/Cancelled.
473 if ($pledgeStatusID && $pledgeStatusID == array_search('Cancelled', $allStatus)) {
474 $paymentStatusID = $pledgeStatusID;
475 $cancelDateClause = ", civicrm_pledge.cancel_date = CURRENT_TIMESTAMP ";
479 $pledgeStatusID = self
::calculatePledgeStatus($pledgeID);
482 if ($pledgeStatusID == array_search('Completed', $allStatus)) {
483 $endDateClause = ", civicrm_pledge.end_date = CURRENT_TIMESTAMP ";
486 //update pledge status
488 UPDATE civicrm_pledge
489 SET civicrm_pledge.status_id = %1
490 {$cancelDateClause} {$endDateClause} {$totalAmountClause}
491 WHERE civicrm_pledge.id = %2
495 1 => array($pledgeStatusID, 'Integer'),
496 2 => array($pledgeID, 'Integer'),
499 $dao = CRM_Core_DAO
::executeQuery($query, $params);
501 return $pledgeStatusID;
505 * Calculate the base scheduled date. This function effectively 'rounds' the $params['scheduled_date'] value
506 * to the first payment date with respect to the frequency day - ie. if payments are on the 15th of the month the date returned
507 * will be the 15th of the relevant month. Then to calculate the payments you can use intervalAdd ie.
508 * CRM_Utils_Date::intervalAdd( $params['frequency_unit'], $i * ($params['frequency_interval']) , calculateBaseScheduledDate( &$params )))
511 * @param array $params
514 * Next scheduled date as an array
516 public static function calculateBaseScheduleDate(&$params) {
518 $scheduled_date = CRM_Utils_Date
::processDate($params['scheduled_date']);
519 $date['year'] = (int) substr($scheduled_date, 0, 4);
520 $date['month'] = (int) substr($scheduled_date, 4, 2);
521 $date['day'] = (int) substr($scheduled_date, 6, 2);
522 //calculation of schedule date according to frequency day of period
523 //frequency day is not applicable for daily installments
524 if ($params['frequency_unit'] != 'day' && $params['frequency_unit'] != 'year') {
525 if ($params['frequency_unit'] != 'week') {
527 //for month use day of next month as next payment date
528 $date['day'] = $params['frequency_day'];
530 elseif ($params['frequency_unit'] == 'week') {
532 //for week calculate day of week ie. Sunday,Monday etc. as next payment date
533 $dayOfWeek = date('w', mktime(0, 0, 0, $date['month'], $date['day'], $date['year']));
534 $frequencyDay = $params['frequency_day'] - $dayOfWeek;
536 $scheduleDate = explode("-", date('n-j-Y', mktime(0, 0, 0, $date['month'],
537 $date['day'] +
$frequencyDay, $date['year']
539 $date['month'] = $scheduleDate[0];
540 $date['day'] = $scheduleDate[1];
541 $date['year'] = $scheduleDate[2];
544 $newdate = date('YmdHis', mktime(0, 0, 0, $date['month'], $date['day'], $date['year']));
549 * Calculate next scheduled pledge payment date. Function calculates next pledge payment date.
551 * @param array $params
552 * must include frequency unit & frequency interval
553 * @param int $paymentNo
554 * number of payment in sequence (e.g. 1 for first calculated payment (treat initial payment as 0)
555 * @param string $basePaymentDate
556 * date to calculate payments from. This would normally be the
557 * first day of the pledge (default) & is calculated off the 'scheduled date' param. Returned date will
558 * be equal to basePaymentDate normalised to fit the 'pledge pattern' + number of installments
563 public static function calculateNextScheduledDate(&$params, $paymentNo, $basePaymentDate = NULL) {
564 if (!$basePaymentDate) {
565 $basePaymentDate = self
::calculateBaseScheduleDate($params);
567 return CRM_Utils_Date
::format(
568 CRM_Utils_Date
::intervalAdd(
569 $params['frequency_unit'],
570 $paymentNo * ($params['frequency_interval']),
577 * Calculate the pledge status.
579 * @param int $pledgeId
583 * $statusId calculated status id of pledge
585 public static function calculatePledgeStatus($pledgeId) {
586 $paymentStatusTypes = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
588 //retrieve all pledge payments for this particular pledge
589 $allPledgePayments = $allStatus = array();
590 $returnProperties = array('status_id');
591 CRM_Core_DAO
::commonRetrieveAll('CRM_Pledge_DAO_PledgePayment', 'pledge_id', $pledgeId, $allPledgePayments, $returnProperties);
593 // build pledge payment statuses
594 foreach ($allPledgePayments as $key => $value) {
595 $allStatus[$value['id']] = $paymentStatusTypes[$value['status_id']];
598 if (array_search('Overdue', $allStatus)) {
599 $statusId = array_search('Overdue', $paymentStatusTypes);
601 elseif (array_search('Completed', $allStatus)) {
602 if (count(array_count_values($allStatus)) == 1) {
603 $statusId = array_search('Completed', $paymentStatusTypes);
606 $statusId = array_search('In Progress', $paymentStatusTypes);
610 $statusId = array_search('Pending', $paymentStatusTypes);
617 * Update pledge payment table.
619 * @param int $pledgeId
621 * @param int $paymentStatusId
622 * Payment status id to set.
623 * @param array $paymentIds
624 * Payment ids to be updated.
625 * @param float|int $actualAmount , actual amount being paid
626 * @param int $contributionId
627 * , Id of associated contribution when payment is recorded.
628 * @param bool $isScriptUpdate
629 * , is function being called from bin script?.
632 public static function updatePledgePayments(
637 $contributionId = NULL,
638 $isScriptUpdate = FALSE
640 $allStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
641 $paymentClause = NULL;
642 if (!empty($paymentIds)) {
643 $payments = implode(',', $paymentIds);
644 $paymentClause = " AND civicrm_pledge_payment.id IN ( {$payments} )";
646 $actualAmountClause = NULL;
647 $contributionIdClause = NULL;
648 if (isset($contributionId) && !$isScriptUpdate) {
649 $contributionIdClause = ", civicrm_pledge_payment.contribution_id = {$contributionId}";
650 $actualAmountClause = ", civicrm_pledge_payment.actual_amount = {$actualAmount}";
654 UPDATE civicrm_pledge_payment
655 SET civicrm_pledge_payment.status_id = {$paymentStatusId}
656 {$actualAmountClause} {$contributionIdClause}
657 WHERE civicrm_pledge_payment.pledge_id = %1
662 $params = array(1 => array($pledgeId, 'Integer'));
664 $dao = CRM_Core_DAO
::executeQuery($query, $params);
668 * Update pledge payment table when reminder is sent.
670 * @param int $paymentId
674 public static function updateReminderDetails($paymentId) {
676 UPDATE civicrm_pledge_payment
677 SET civicrm_pledge_payment.reminder_date = CURRENT_TIMESTAMP,
678 civicrm_pledge_payment.reminder_count = civicrm_pledge_payment.reminder_count + 1
679 WHERE civicrm_pledge_payment.id = {$paymentId}
681 $dao = CRM_Core_DAO
::executeQuery($query);
685 * Get oldest pending or in progress pledge payments.
687 * @param int $pledgeID
693 * associated array of pledge details
695 public static function getOldestPledgePayment($pledgeID, $limit = 1) {
696 //get pending / overdue statuses
697 $pledgeStatuses = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
699 //get pending and overdue payments
700 $status[] = array_search('Pending', $pledgeStatuses);
701 $status[] = array_search('Overdue', $pledgeStatuses);
703 $statusClause = " IN (" . implode(',', $status) . ")";
706 SELECT civicrm_pledge_payment.id id, civicrm_pledge_payment.scheduled_amount amount, civicrm_pledge_payment.currency, civicrm_pledge_payment.scheduled_date,civicrm_pledge.financial_type_id
707 FROM civicrm_pledge, civicrm_pledge_payment
708 WHERE civicrm_pledge.id = civicrm_pledge_payment.pledge_id
709 AND civicrm_pledge_payment.status_id {$statusClause}
710 AND civicrm_pledge.id = %1
711 ORDER BY civicrm_pledge_payment.scheduled_date ASC
715 $params[1] = array($pledgeID, 'Integer');
716 $params[2] = array($limit, 'Integer');
717 $payment = CRM_Core_DAO
::executeQuery($query, $params);
719 $paymentDetails = array();
720 while ($payment->fetch()) {
721 $paymentDetails[] = array(
722 'id' => $payment->id
,
723 'amount' => $payment->amount
,
724 'currency' => $payment->currency
,
725 'schedule_date' => $payment->scheduled_date
,
726 'financial_type_id' => $payment->financial_type_id
,
731 return end($paymentDetails);
735 * @param int $pledgeID
736 * @param $actualAmount
737 * @param $pledgeScheduledAmount
738 * @param int $paymentContributionId
739 * @param int $pPaymentId
740 * @param int $paymentStatusID
742 public static function adjustPledgePayment($pledgeID, $actualAmount, $pledgeScheduledAmount, $paymentContributionId = NULL, $pPaymentId = NULL, $paymentStatusID = NULL) {
743 $allStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
744 if ($paymentStatusID == array_search('Cancelled', $allStatus) ||
$paymentStatusID == array_search('Refunded', $allStatus)) {
746 SELECT civicrm_pledge_payment.id id
747 FROM civicrm_pledge_payment
748 WHERE civicrm_pledge_payment.contribution_id = {$paymentContributionId}
750 $paymentsAffected = CRM_Core_DAO
::executeQuery($query);
751 $paymentIDs = array();
752 while ($paymentsAffected->fetch()) {
753 $paymentIDs[] = $paymentsAffected->id
;
755 // Reset the affected values by the amount paid more than the scheduled amount
756 foreach ($paymentIDs as $key => $value) {
757 $payment = new CRM_Pledge_DAO_PledgePayment();
758 $payment->id
= $value;
759 if ($payment->find(TRUE)) {
760 $payment->contribution_id
= 'null';
761 $payment->status_id
= array_search('Pending', $allStatus);
762 $payment->scheduled_date
= NULL;
763 $payment->reminder_date
= NULL;
764 $payment->scheduled_amount
= $pledgeScheduledAmount;
765 $payment->actual_amount
= 'null';
770 //Cancel the initial paid amount
771 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment', reset($paymentIDs), 'status_id', $paymentStatusID, 'id');
772 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment', reset($paymentIDs), 'actual_amount', $actualAmount, 'id');
774 //Add new payment after the last payment for the pledge
775 $allPayments = self
::getPledgePayments($pledgeID);
776 $lastPayment = array_pop($allPayments);
778 $pledgeFrequencyUnit = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_Pledge', $pledgeID, 'frequency_unit', 'id');
779 $pledgeFrequencyInterval = CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_Pledge', $pledgeID, 'frequency_interval', 'id');
780 $pledgeScheduledDate = $lastPayment['scheduled_date'];
781 $scheduled_date = CRM_Utils_Date
::processDate($pledgeScheduledDate);
782 $date['year'] = (int) substr($scheduled_date, 0, 4);
783 $date['month'] = (int) substr($scheduled_date, 4, 2);
784 $date['day'] = (int) substr($scheduled_date, 6, 2);
785 $newDate = date('YmdHis', mktime(0, 0, 0, $date['month'], $date['day'], $date['year']));
786 $ScheduledDate = CRM_Utils_Date
::format(CRM_Utils_Date
::intervalAdd($pledgeFrequencyUnit, $pledgeFrequencyInterval, $newDate));
787 $pledgeParams = array(
788 'status_id' => array_search('Pending', $allStatus),
789 'pledge_id' => $pledgeID,
790 'scheduled_amount' => $pledgeScheduledAmount,
791 'scheduled_date' => $ScheduledDate,
793 $payment = self
::add($pledgeParams);
796 $oldestPayment = self
::getOldestPledgePayment($pledgeID);
797 if (!$paymentContributionId) {
798 // means we are editing payment scheduled payment, so get the second pending to update.
799 $oldestPayment = self
::getOldestPledgePayment($pledgeID, 2);
800 if (($oldestPayment['count'] != 1) && ($oldestPayment['id'] == $pPaymentId)) {
801 $oldestPayment = self
::getOldestPledgePayment($pledgeID);
805 if ($oldestPayment) {
806 // not the last scheduled payment and the actual amount is less than the expected , add it to oldest pending.
807 if (($actualAmount != $pledgeScheduledAmount) && (($actualAmount < $pledgeScheduledAmount) ||
(($actualAmount - $pledgeScheduledAmount) < $oldestPayment['amount']))) {
808 $oldScheduledAmount = $oldestPayment['amount'];
809 $newScheduledAmount = $oldScheduledAmount +
($pledgeScheduledAmount - $actualAmount);
810 //store new amount in oldest pending payment record.
811 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment',
812 $oldestPayment['id'],
816 if (CRM_Core_DAO
::getFieldValue('CRM_Pledge_DAO_PledgePayment', $oldestPayment['id'], 'contribution_id', 'id')) {
817 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment',
818 $oldestPayment['id'],
820 $paymentContributionId
824 elseif (($actualAmount > $pledgeScheduledAmount) && (($actualAmount - $pledgeScheduledAmount) >= $oldestPayment['amount'])) {
825 // here the actual amount is greater than expected and also greater than the next installment amount, so update the next installment as complete and again add it to next subsequent pending payment
826 // set the actual amount of the next pending to '0', set contribution Id to current contribution Id and status as completed
827 $paymentId = array($oldestPayment['id']);
828 self
::updatePledgePayments($pledgeID, array_search('Completed', $allStatus), $paymentId, 0, $paymentContributionId);
829 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment', $oldestPayment['id'], 'scheduled_amount', 0, 'id');
830 $oldestPayment = self
::getOldestPledgePayment($pledgeID);
831 if (!$paymentContributionId) {
832 // means we are editing payment scheduled payment.
833 $oldestPaymentAmount = self
::getOldestPledgePayment($pledgeID, 2);
835 $newActualAmount = ($actualAmount - $pledgeScheduledAmount);
836 $newPledgeScheduledAmount = $oldestPayment['amount'];
837 if (!$paymentContributionId) {
838 $newActualAmount = ($actualAmount - $pledgeScheduledAmount);
839 $newPledgeScheduledAmount = $oldestPaymentAmount['amount'];
840 // means we are editing payment scheduled payment, so update scheduled amount.
841 CRM_Core_DAO
::setFieldValue('CRM_Pledge_DAO_PledgePayment',
842 $oldestPaymentAmount['id'],
847 if ($newActualAmount > 0) {
848 self
::adjustPledgePayment($pledgeID, $newActualAmount, $newPledgeScheduledAmount, $paymentContributionId);