diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index f05efcfd92b6..12e055528def 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -5356,9 +5356,9 @@ protected static function getFinancialItemAmountFromParams($params, $context, $l elseif ($context == 'changedStatus') { $cancelledTaxAmount = 0; if ($isARefund) { - $cancelledTaxAmount = CRM_Utils_Array::value('tax_amount', $params, '0.00'); + $cancelledTaxAmount = CRM_Utils_Array::value('tax_amount', $lineItemDetails, '0.00'); } - return self::getMultiplier($params['contribution']->contribution_status_id, $context) * ((float) $params['trxnParams']['total_amount'] + (float) $cancelledTaxAmount); + return self::getMultiplier($params['contribution']->contribution_status_id, $context) * ((float) $lineItemDetails['line_total'] + (float) $cancelledTaxAmount); } elseif ($context === NULL) { // erm, yes because? but, hey, it's tested. @@ -5371,7 +5371,7 @@ protected static function getFinancialItemAmountFromParams($params, $context, $l return $params['total_amount']; } else { - return self::getMultiplier($params['contribution']->contribution_status_id, $context) * $lineItemDetails['line_total']; + return self::getMultiplier($params['contribution']->contribution_status_id, $context) * ((float) $lineItemDetails['line_total']); } } diff --git a/tests/phpunit/CRM/Member/Form/MembershipRenewalTest.php b/tests/phpunit/CRM/Member/Form/MembershipRenewalTest.php index be1d40135945..d95e2804b9fb 100644 --- a/tests/phpunit/CRM/Member/Form/MembershipRenewalTest.php +++ b/tests/phpunit/CRM/Member/Form/MembershipRenewalTest.php @@ -137,8 +137,9 @@ public function tearDown() { 'civicrm_address', ) ); - $this->callAPISuccess('contact', 'delete', array('id' => 17, 'skip_undelete' => TRUE)); - $this->callAPISuccess('contact', 'delete', array('id' => 23, 'skip_undelete' => TRUE)); + foreach (array(17, 18, 23, 32) as $contactID) { + $this->callAPISuccess('contact', 'delete', array('id' => $contactID, 'skip_undelete' => TRUE)); + } $this->callAPISuccess('relationship_type', 'delete', array('id' => 20)); } diff --git a/tests/phpunit/CRM/Member/Form/MembershipTest.php b/tests/phpunit/CRM/Member/Form/MembershipTest.php index 09476038bc60..18cf759ed358 100644 --- a/tests/phpunit/CRM/Member/Form/MembershipTest.php +++ b/tests/phpunit/CRM/Member/Form/MembershipTest.php @@ -137,8 +137,9 @@ public function tearDown() { 'civicrm_uf_match', ) ); - $this->callAPISuccess('contact', 'delete', array('id' => 17, 'skip_undelete' => TRUE)); - $this->callAPISuccess('contact', 'delete', array('id' => 23, 'skip_undelete' => TRUE)); + foreach (array(17, 18, 23, 32) as $contactID) { + $this->callAPISuccess('contact', 'delete', array('id' => $contactID, 'skip_undelete' => TRUE)); + } $this->callAPISuccess('relationship_type', 'delete', array('id' => 20)); } @@ -684,6 +685,126 @@ public function testFormStatusUpdate() { $this->assertEquals($membership['status_id'], $previousStatus); } + /** + * CRM-20946: Test the financial entires especially the reversed amount, + * after related Contribution is cancelled + */ + public function testFinancialEntiriesOnCancelledContribution() { + $form = $this->getForm(NULL); + $form->preProcess(); + $this->createLoggedInUser(); + + // create a price-set of price-field of type checkbox and each price-option corrosponds to a membership type + $priceSet = $this->callAPISuccess('price_set', 'create', array( + 'is_quick_config' => 0, + 'extends' => 'CiviMember', + 'financial_type_id' => 1, + 'title' => 'my Page', + )); + $priceSetID = $priceSet['id']; + // create respective checkbox price-field + $priceField = $this->callAPISuccess('price_field', 'create', array( + 'price_set_id' => $priceSetID, + 'label' => 'Memberships', + 'html_type' => 'Checkbox', + )); + $priceFieldID = $priceField['id']; + // create two price options, each represent a membership type of amount 20 and 10 respectively + $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array( + 'price_set_id' => $priceSetID, + 'price_field_id' => $priceField['id'], + 'label' => 'Long Haired Goat', + 'amount' => 20, + 'financial_type_id' => 'Donation', + 'membership_type_id' => 15, + 'membership_num_terms' => 1, + ) + ); + $pfvIDs = array($priceFieldValue['id'] => 1); + $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array( + 'price_set_id' => $priceSetID, + 'price_field_id' => $priceField['id'], + 'label' => 'Shoe-eating Goat', + 'amount' => 10, + 'financial_type_id' => 'Donation', + 'membership_type_id' => 35, + 'membership_num_terms' => 2, + ) + ); + $pfvIDs[$priceFieldValue['id']] = 1; + + // register for both of this memberships via backoffice membership form submission + $params = array( + 'cid' => $this->_individualId, + 'join_date' => date('m/d/Y', time()), + 'start_date' => '', + 'end_date' => '', + // This format reflects the 23 being the organisation & the 25 being the type. + "price_$priceFieldID" => $pfvIDs, + "price_set_id" => $priceSetID, + 'membership_type_id' => array(1 => 0), + 'auto_renew' => '0', + 'max_related' => '', + 'num_terms' => '2', + 'source' => '', + 'total_amount' => '30.00', + //Member dues, see data.xml + 'financial_type_id' => '2', + 'soft_credit_type_id' => '', + 'soft_credit_contact_id' => '', + 'payment_instrument_id' => 4, + 'from_email_address' => '"Demonstrators Anonymous" ', + 'receipt_text_signup' => 'Thank you text', + 'payment_processor_id' => $this->_paymentProcessorID, + 'record_contribution' => TRUE, + 'trxn_id' => 777, + 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Pending'), + 'billing_first_name' => 'Test', + 'billing_middlename' => 'Last', + 'billing_street_address-5' => '10 Test St', + 'billing_city-5' => 'Test', + 'billing_state_province_id-5' => '1003', + 'billing_postal_code-5' => '90210', + 'billing_country_id-5' => '1228', + ); + $form->testSubmit($params); + + // cancel the related contribution via API + $contribution = $this->callAPISuccessGetSingle('Contribution', array( + 'contact_id' => $this->_individualId, + 'contribution_status_id' => 2, + )); + $this->callAPISuccess('Contribution', 'create', array( + 'id' => $contribution['id'], + 'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Cancelled'), + )); + + // fetch financial_trxn ID of the related contribution + $sql = "SELECT financial_trxn_id + FROM civicrm_entity_financial_trxn + WHERE entity_id = %1 AND entity_table = 'civicrm_contribution' + ORDER BY id DESC + LIMIT 1 + "; + $financialTrxnID = CRM_Core_DAO::singleValueQuery($sql, array(1 => array($contribution['id'], 'Int'))); + + // fetch entity_financial_trxn records and compare their cancelled records + $result = $this->callAPISuccess('EntityFinancialTrxn', 'Get', array( + 'financial_trxn_id' => $financialTrxnID, + 'entity_table' => 'civicrm_financial_item', + )); + // compare the reversed amounts of respective memberships after cancelling contribution + $cancelledMembershipAmounts = array( + -20.00, + -10.00, + ); + $count = 0; + foreach ($result['values'] as $record) { + $this->assertEquals($cancelledMembershipAmounts[$count], $record['amount']); + $count++; + } + } + /** * Test the submit function of the membership form. */ diff --git a/tests/phpunit/CRM/Member/Form/dataset/data.xml b/tests/phpunit/CRM/Member/Form/dataset/data.xml index 65a279e9548b..9655cea473ad 100644 --- a/tests/phpunit/CRM/Member/Form/dataset/data.xml +++ b/tests/phpunit/CRM/Member/Form/dataset/data.xml @@ -10,6 +10,15 @@ first_name="Joe" last_name="Blow" /> + + - +