From a0e872f12e7b1bf855a1e4d645ba68d12af4fb83 Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Mon, 13 Jul 2020 14:38:20 +1000 Subject: [PATCH] [REF] permit negative payments to be made against completed payments Add in unit test for adding additional refund payment to contribution already refunded and also adding a negative payment to a contribution that is negative already --- CRM/Financial/BAO/Payment.php | 11 ++++++++-- tests/phpunit/api/v3/PaymentTest.php | 32 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CRM/Financial/BAO/Payment.php b/CRM/Financial/BAO/Payment.php index e13837e996..2b93c545e1 100644 --- a/CRM/Financial/BAO/Payment.php +++ b/CRM/Financial/BAO/Payment.php @@ -487,6 +487,9 @@ class CRM_Financial_BAO_Payment { if ($outstandingBalance !== 0.0) { $ratio = $params['total_amount'] / $outstandingBalance; } + elseif ($params['total_amount'] < 0) { + $ratio = $params['total_amount'] / (float) CRM_Core_BAO_FinancialTrxn::getTotalPayments($params['contribution_id'], TRUE); + } else { // Help we are making a payment but no money is owed. We won't allocate the overpayment to any line item. $ratio = 0; @@ -496,12 +499,16 @@ class CRM_Financial_BAO_Payment { $lineItems[$lineItemID]['id'] = $lineItemID; $lineItems[$lineItemID]['paid'] = self::getAmountOfLineItemPaid($lineItemID); $lineItems[$lineItemID]['balance'] = $lineItem['subTotal'] - $lineItems[$lineItemID]['paid']; - if (!empty($lineItemOverrides)) { $lineItems[$lineItemID]['allocation'] = $lineItemOverrides[$lineItemID] ?? NULL; } else { - $lineItems[$lineItemID]['allocation'] = $lineItems[$lineItemID]['balance'] * $ratio; + if (empty($lineItems[$lineItemID]['balance']) && !empty($ratio) && $params['total_amount'] < 0) { + $lineItems[$lineItemID]['allocation'] = $lineItem['subTotal'] * $ratio; + } + else { + $lineItems[$lineItemID]['allocation'] = $lineItems[$lineItemID]['balance'] * $ratio; + } } } return $lineItems; diff --git a/tests/phpunit/api/v3/PaymentTest.php b/tests/phpunit/api/v3/PaymentTest.php index 4ae47f9200..5c36bde5d2 100644 --- a/tests/phpunit/api/v3/PaymentTest.php +++ b/tests/phpunit/api/v3/PaymentTest.php @@ -183,6 +183,7 @@ class api_v3_PaymentTest extends CiviUnitTestCase { ], ]; $this->checkPaymentResult($payment, $expectedResult); + $this->callAPISuccess('Payment', 'create', ['total_amount' => '-20', 'contribution_id' => $contributionID2]); $this->validateAllPayments(); } @@ -213,6 +214,37 @@ class api_v3_PaymentTest extends CiviUnitTestCase { ]); } + /** + * Test full refund when no payment has actually been record. + */ + public function testFullRefundWithPaymentAlreadyRefunded() { + $params1 = [ + 'contact_id' => $this->_individualId, + 'trxn_id' => 111111, + 'total_amount' => 10, + ]; + $contributionID1 = $this->contributionCreate($params1); + $paymentParams = ['contribution_id' => $contributionID1]; + $this->callAPISuccess('Payment', 'create', ['total_amount' => '-10', 'contribution_id' => $contributionID1]); + $payment = $this->callAPISuccess('payment', 'get', $paymentParams); + $this->callAPISuccess('Payment', 'create', ['total_amount' => '-10', 'contribution_id' => $contributionID1]); + $payment = $this->callAPISuccess('payment', 'get', $paymentParams); + $this->validateAllPayments(); + } + + public function testNegativePaymentWithNegativeContribution() { + $params1 = [ + 'contact_id' => $this->_individualId, + 'trxn_id' => 111111, + 'total_amount' => -10, + ]; + $contributionID1 = $this->contributionCreate($params1); + $this->callAPISuccess('Payment', 'create', ['total_amount' => '-20', 'contribution_id' => $contributionID1]); + $paymentParams = ['contribution_id' => $contributionID1]; + $payment = $this->callAPISuccess('payment', 'get', $paymentParams); + $this->validateAllPayments(); + } + /** * Test email receipt for partial payment. * -- 2.25.1