From 15816cb4757acdb3142d4286188542896fce3ed6 Mon Sep 17 00:00:00 2001 From: Allen Shaw Date: Fri, 14 Apr 2017 17:24:51 -0500 Subject: [PATCH] CRM-20172: Added test and fix for correct amounts. --- CRM/Contribute/Form/Contribution/Confirm.php | 17 +++- tests/phpunit/api/v3/ContributionPageTest.php | 96 ++++++++++++++++++- 2 files changed, 110 insertions(+), 3 deletions(-) diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php index 55844c1b68..3e9cb84e0f 100644 --- a/CRM/Contribute/Form/Contribution/Confirm.php +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -1475,6 +1475,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr $isTest, $isRecurForFirstTransaction ); + $paymentResults[] = array('contribution_id' => $paymentResult['contribution']->id, 'result' => $paymentResult); if (!empty($paymentResult['contribution'])) { $this->postProcessPremium($premiumParams, $paymentResult['contribution']); @@ -1644,8 +1645,12 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr // CRM-19792 : set necessary fields for payment processor CRM_Core_Payment_Form::mapParams($form->_bltID, $paymentParams, $paymentParams, TRUE); - $paymentActionResult = $payment->doPayment($paymentParams, 'contribute'); - $paymentResults[] = array('contribution_id' => $paymentResult['contribution']->id, 'result' => $paymentActionResult); + // If this is a single membership-related contribution, it won't have + // be performed yet, so do it now. + if ($isPaidMembership && !$isProcessSeparateMembershipTransaction) { + $paymentActionResult = $payment->doPayment($paymentParams, 'contribute'); + $paymentResults[] = array('contribution_id' => $paymentResult['contribution']->id, 'result' => $paymentActionResult); + } // Do not send an email if Recurring transaction is done via Direct Mode // Email will we sent when the IPN is received. foreach ($paymentResults as $result) { @@ -1780,6 +1785,14 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr ); $result = array(); + + if ($tempParams['skipLineItem']) { + // We are not processing the line item here because we are processing a membership. + // So unset the total_amount param, which stores the non-membership contribution amount. + $tempParams['total_amount'] = $membershipContribution->total_amount; + $tempParams['contributionID'] = $membershipContribution->id; + } + if ($form->_values['is_monetary'] && !$form->_params['is_pay_later'] && $minimumFee > 0.0) { // At the moment our tests are calling this form in a way that leaves 'object' empty. For // now we compensate here. diff --git a/tests/phpunit/api/v3/ContributionPageTest.php b/tests/phpunit/api/v3/ContributionPageTest.php index 9765868aa0..6689dc5331 100644 --- a/tests/phpunit/api/v3/ContributionPageTest.php +++ b/tests/phpunit/api/v3/ContributionPageTest.php @@ -41,6 +41,7 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase { protected $_entity = 'contribution_page'; protected $contribution_result = NULL; protected $_priceSetParams = array(); + protected $_membershipBlockAmount = 2; /** * Payment processor details. * @var array @@ -626,6 +627,79 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase { $mut->clearMessages(); } + /** + * Test submit with a membership block in place. + * + * Ensure a separate payment for the membership vs the contribution, with + * correct amounts. + */ + public function testSubmitMembershipBlockIsSeparatePaymentPaymentProcessorNowChargesCorrectAmounts() { + $this->setUpMembershipContributionPage(TRUE); + $processor = Civi\Payment\System::singleton()->getById($this->_paymentProcessor['id']); + $processor->setDoDirectPaymentResult(array('fee_amount' => .72)); + $test_uniq = uniqid(); + $contributionPageAmount = 10; + $submitParams = array( + 'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']), + 'id' => (int) $this->_ids['contribution_page'], + 'amount' => $contributionPageAmount, + 'billing_first_name' => 'Billy', + 'billing_middle_name' => 'Goat', + 'billing_last_name' => 'Gruff', + 'email-Primary' => 'henry@8th.king', + 'selectMembership' => $this->_ids['membership_type'], + 'payment_processor_id' => $this->_paymentProcessor['id'], + 'credit_card_number' => '4111111111111111', + 'credit_card_type' => 'Visa', + 'credit_card_exp_date' => array('M' => 9, 'Y' => 2040), + 'cvv2' => 123, + 'TEST_UNIQ' => $test_uniq, + ); + + // set custom hook + $this->hookClass->setHook('civicrm_alterPaymentProcessorParams', array($this, 'hook_civicrm_alterPaymentProcessorParams')); + + $this->callAPISuccess('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL); + $contributions = $this->callAPISuccess('contribution', 'get', array( + 'contribution_page_id' => $this->_ids['contribution_page'], + 'contribution_status_id' => 1, + )); + + $result = civicrm_api3('SystemLog', 'get', array( + 'sequential' => 1, + 'message' => array('LIKE' => "%{$test_uniq}%"), + )); + $this->assertCount(2, $result['values'], "Expected exactly 2 log entries matching {$test_uniq}."); + + // Examine logged entries to ensure correct values. + $contribution_ids = array(); + $found_membership_amount = $found_contribution_amount = FALSE; + foreach ($result['values'] as $value) { + list($junk, $json) = explode("$test_uniq:", $value['message']); + $logged_contribution = json_decode($json, TRUE); + $contribution_ids[] = $logged_contribution['contributionID']; + if (!empty($logged_contribution['total_amount'])) { + $amount = $logged_contribution['total_amount']; + } + else { + $amount = $logged_contribution['amount']; + } + + if ($amount == $this->_membershipBlockAmount) { + $found_membership_amount = TRUE; + } + if ($amount == $contributionPageAmount) { + $found_contribution_amount = TRUE; + } + } + + $distinct_contribution_ids = array_unique($contribution_ids); + $this->assertCount(2, $distinct_contribution_ids, "Expected exactly 2 log contributions with distinct contributionIDs."); + $this->assertTrue($found_contribution_amount, "Expected one log contribution with amount '$contributionPageAmount' (the contribution page amount)"); + $this->assertTrue($found_membership_amount, "Expected one log contribution with amount '$this->_membershipBlockAmount' (the membership amount)"); + + } + /** * Test that when a transaction fails the pending contribution remains. * @@ -1150,7 +1224,7 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase { $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array( 'name' => 'membership_amount', 'label' => 'Membership Amount', - 'amount' => 2, + 'amount' => $this->_membershipBlockAmount, 'financial_type_id' => 'Donation', 'format.only_id' => TRUE, 'membership_type_id' => $membershipTypeID, @@ -1529,4 +1603,24 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase { $this->assertEquals($lineItem_TaxAmount, round($submitParams['tax_amount'], 2), 'Wrong Sales Tax Amount is calculated and stored.'); } + public function hook_civicrm_alterPaymentProcessorParams($paymentObj, &$rawParams, &$cookedParams) { + // Ensure total_amount are the same if they're both given. + $total_amount = CRM_Utils_Array::value('total_amount', $rawParams); + $amount = CRM_Utils_Array::value('amount', $rawParams); + if (!empty($total_amount) && !empty($amount) && $total_amount != $amount) { + throw new Exception("total_amount '$total_amount' and amount '$amount' differ."); + } + + // Log parameters for later debugging and testing. + $message = __FUNCTION__ . ": {$rawParams['TEST_UNIQ']}:"; + $log_params = array_intersect_key($rawParams, array( + 'amount' => 1, + 'total_amount' => 1, + 'contributionID' => 1, + )); + $message .= json_encode($log_params); + $log = new CRM_Utils_SystemLogger(); + $log->debug($message, $_REQUEST); + } + } -- 2.25.1