Skip to content

Commit

Permalink
Remove 'partially paid' as a contribution status option for 'record p…
Browse files Browse the repository at this point in the history
…ayment'

Fixes a bug where it is possible to select contribution statuses that do not result in valid financial
transactions. Specifically the 'Partially Paid' option creates no payment transaction and any subsequent
financial_trxns get the wrong line item allocations as a result.
  • Loading branch information
eileenmcnaughton committed Nov 11, 2019
1 parent b283391 commit eaba6ea
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 24 deletions.
16 changes: 10 additions & 6 deletions CRM/Contribute/BAO/Contribution/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ public static function formatAmount($amount, $decimals = 2) {
* Array of contribution statuses in array('status id' => 'label') format
*/
public static function getContributionStatuses($usedFor = 'contribution', $id = NULL) {
if ($usedFor == 'pledge') {
if ($usedFor === 'pledge') {
$statusNames = CRM_Pledge_BAO_Pledge::buildOptions('status_id', 'validate');
}
else {
Expand All @@ -562,25 +562,29 @@ public static function getContributionStatuses($usedFor = 'contribution', $id =
'Pending refund',
]);

// Event registration and New Membership backoffice form support partially paid payment,
// so exclude this status only for 'New Contribution' form
if ($usedFor == 'contribution') {
if ($usedFor === 'contribution') {
$statusNamesToUnset = array_merge($statusNamesToUnset, [
'In Progress',
'Overdue',
'Partially paid',
]);
}
elseif ($usedFor == 'participant') {
elseif ($usedFor === 'participant') {
$statusNamesToUnset = array_merge($statusNamesToUnset, [
'Cancelled',
'Failed',
'In Progress',
'Overdue',
'Partially paid',
]);
}
elseif ($usedFor == 'membership') {
elseif ($usedFor === 'membership') {
$statusNamesToUnset = array_merge($statusNamesToUnset, [
'In Progress',
'Cancelled',
'Failed',
'Overdue',
'Partially paid',
]);
}
}
Expand Down
34 changes: 16 additions & 18 deletions tests/phpunit/CRM/Member/Form/MembershipTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ public function testSubmitPartialPayment($thousandSeparator) {
$this->createLoggedInUser();
$priceSet = $this->callAPISuccess('PriceSet', 'Get', ["extends" => "CiviMember"]);
$form->set('priceSetId', $priceSet['id']);
$partiallyPaidAmount = 25;

CRM_Price_BAO_PriceSet::buildPriceSet($form);
$params = [
'cid' => $this->_individualId,
Expand All @@ -668,9 +668,9 @@ public function testSubmitPartialPayment($thousandSeparator) {
'membership_type_id' => [23, $this->membershipTypeAnnualFixedID],
'receive_date' => date('Y-m-d', time()) . ' 20:36:00',
'record_contribution' => 1,
'total_amount' => $this->formatMoneyInput($partiallyPaidAmount),
'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Partially paid'),
'total_amount' => $this->formatMoneyInput(50),
'payment_instrument_id' => array_search('Check', $this->paymentInstruments, TRUE),
'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'),
//Member dues, see data.xml
'financial_type_id' => '2',
'payment_processor_id' => $this->_paymentProcessorID,
Expand All @@ -679,41 +679,39 @@ public function testSubmitPartialPayment($thousandSeparator) {
$form->testSubmit($params);
$membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
// check the membership status after partial payment, if its Pending
$this->assertEquals(array_search('Pending', CRM_Member_PseudoConstant::membershipStatus()), $membership['status_id']);
$contribution = $this->callAPISuccessGetSingle('Contribution', [
'contact_id' => $this->_individualId,
]);
$this->assertEquals(array_search('Pending', CRM_Member_PseudoConstant::membershipStatus(), TRUE), $membership['status_id']);
$contribution = $this->callAPISuccessGetSingle('Contribution', ['contact_id' => $this->_individualId]);
$this->callAPISuccess('Payment', 'create', ['contribution_id' => $contribution['id'], 'total_amount' => 25, 'payment_instrument_id' => 'Cash']);
$contribution = $this->callAPISuccessGetSingle('Contribution', ['id' => $contribution['id']]);
$this->assertEquals('Partially paid', $contribution['contribution_status']);
// $this->assertEquals(50.00, $contribution['total_amount']);
// $this->assertEquals(25.00, $contribution['net_amount']);

// Step 2: submit the other half of the partial payment
// via AdditionalPayment form to complete the related contribution
$form = new CRM_Contribute_Form_AdditionalPayment();
$submitParams = [
'contribution_id' => $contribution['contribution_id'],
'contact_id' => $this->_individualId,
'total_amount' => $this->formatMoneyInput($partiallyPaidAmount),
'total_amount' => $this->formatMoneyInput(25),
'currency' => 'USD',
'financial_type_id' => 2,
'receive_date' => '2015-04-21 23:27:00',
'trxn_date' => '2017-04-11 13:05:11',
'payment_processor_id' => 0,
'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
'payment_instrument_id' => array_search('Check', $this->paymentInstruments, TRUE),
'check_number' => 'check-12345',
];
$form->cid = $this->_individualId;
$form->testSubmit($submitParams);
$membership = $this->callAPISuccessGetSingle('Membership', ['contact_id' => $this->_individualId]);
// check the membership status after additional payment, if its changed to 'New'
$this->assertEquals(array_search('New', CRM_Member_PseudoConstant::membershipStatus()), $membership['status_id']);
$this->assertEquals(array_search('New', CRM_Member_PseudoConstant::membershipStatus(), TRUE), $membership['status_id']);

// check the contribution status and net amount after additional payment
$contribution = $this->callAPISuccessGetSingle('Contribution', [
'contact_id' => $this->_individualId,
]);
$this->assertEquals('Completed', $contribution['contribution_status']);
// $this->assertEquals(50.00, $contribution['net_amount']);
$this->validateAllPayments();
}

/**
Expand All @@ -724,14 +722,14 @@ public function testSubmitPartialPayment($thousandSeparator) {
public function testSubmitRecur() {
CRM_Core_Session::singleton()->getStatus(TRUE);
$pendingVal = $this->callAPISuccessGetValue('OptionValue', [
'return' => "id",
'option_group_id' => "contribution_status",
'label' => "Pending Label**",
'return' => 'id',
'option_group_id' => 'contribution_status',
'label' => 'Pending Label**',
]);
//Update label for Pending contribution status.
$this->callAPISuccess('OptionValue', 'create', [
'id' => $pendingVal,
'label' => "PendingEdited",
'label' => 'PendingEdited',
]);

$form = $this->getForm();
Expand Down

0 comments on commit eaba6ea

Please sign in to comment.