From 84fcdb679f46e459cfc65a5149a92ee42986c876 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Tue, 3 Jan 2023 12:06:09 +1300 Subject: [PATCH] Extend testing for ContributionConfirm & consolidate isSeparateMembershipPayment --- CRM/Contribute/BAO/ContributionPage.php | 2 + CRM/Contribute/Form/Contribution/Confirm.php | 24 ++-- CRM/Contribute/Form/ContributionBase.php | 12 ++ .../Form/Contribution/ConfirmTest.php | 105 +++++++++++++----- .../CRM/Contribute/Form/ContributionTest.php | 11 +- .../CRMTraits/Financial/PriceSetTrait.php | 25 ++++- tests/phpunit/CiviTest/CiviUnitTestCase.php | 21 +++- 7 files changed, 153 insertions(+), 47 deletions(-) diff --git a/CRM/Contribute/BAO/ContributionPage.php b/CRM/Contribute/BAO/ContributionPage.php index 43c88cfbbc..9945d10286 100644 --- a/CRM/Contribute/BAO/ContributionPage.php +++ b/CRM/Contribute/BAO/ContributionPage.php @@ -946,8 +946,10 @@ LEFT JOIN civicrm_premiums ON ( civicrm_premiums.entity_id = civicrm * * @return bool * isSeparateMembershipPayment + * @deprecated */ public static function getIsMembershipPayment($id) { + CRM_Core_Error::deprecatedFunctionWarning('api'); $membershipBlocks = civicrm_api3('membership_block', 'get', [ 'entity_table' => 'civicrm_contribution_page', 'entity_id' => $id, diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php index 891ebcbc5b..14ca1f7b81 100644 --- a/CRM/Contribute/Form/Contribution/Confirm.php +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -568,8 +568,8 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr $this->buildCustom($this->_values['onbehalf_profile_id'], 'onbehalfProfile', TRUE, 'onbehalf', $fieldTypes); } - $this->_separateMembershipPayment = $this->get('separateMembershipPayment'); - $this->assign('is_separate_payment', $this->_separateMembershipPayment); + $this->_separateMembershipPayment = $this->isSeparateMembershipPayment(); + $this->assign('is_separate_payment', $this->isSeparateMembershipPayment()); $this->assign('priceSetID', $this->_priceSetId); @@ -1446,7 +1446,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr //enabled and contribution amount is not selected. fix for CRM-3010 $isPaidMembership = TRUE; } - $isProcessSeparateMembershipTransaction = $this->isSeparateMembershipTransaction($this->_id); + $isProcessSeparateMembershipTransaction = $this->isSeparateMembershipTransaction(); if ($this->isFormSupportsNonMembershipContributions()) { $financialTypeID = $this->_values['financial_type_id']; @@ -1911,16 +1911,14 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr * contribution * transaction AND a membership transaction AND the payment processor supports double financial transactions (ie. NOT doTransferCheckout style) * - * @param int $formID + * @todo - this is confusing - does isSeparateMembershipPayment need to + * check both conditions, making this redundant, or are there 2 legit + * variations here? * * @return bool */ - protected function isSeparateMembershipTransaction($formID): bool { - $memBlockDetails = CRM_Member_BAO_Membership::getMembershipBlock($formID); - if (!empty($memBlockDetails['is_separate_payment']) && $this->isFormSupportsNonMembershipContributions()) { - return TRUE; - } - return FALSE; + protected function isSeparateMembershipTransaction(): bool { + return $this->isSeparateMembershipPayment() && $this->isFormSupportsNonMembershipContributions(); } /** @@ -2004,7 +2002,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr $form->_id = $params['id']; CRM_Contribute_BAO_ContributionPage::setValues($form->_id, $form->_values); - $form->_separateMembershipPayment = CRM_Contribute_BAO_ContributionPage::getIsMembershipPayment($form->_id); + $form->_separateMembershipPayment = $form->isSeparateMembershipPayment(); //this way the mocked up controller ignores the session stuff $_SERVER['REQUEST_METHOD'] = 'GET'; $form->controller = new CRM_Contribute_Controller_Contribution(); @@ -2015,12 +2013,12 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr $order = new CRM_Financial_BAO_Order(); $order->setPriceSetIDByContributionPageID($params['id']); $order->setPriceSelectionFromUnfilteredInput($params); - if (isset($params['amount']) && !CRM_Contribute_BAO_ContributionPage::getIsMembershipPayment($form->_id)) { + if (isset($params['amount']) && !$form->isSeparateMembershipPayment()) { // @todo deprecate receiving amount, calculate on the form. $order->setOverrideTotalAmount((float) $params['amount']); } $amount = $order->getTotalAmount(); - if ($form->_separateMembershipPayment) { + if ($form->isSeparateMembershipPayment()) { $amount -= $order->getMembershipTotalAmount(); } $form->_amount = $params['amount'] = $form->_params['amount'] = $amount; diff --git a/CRM/Contribute/Form/ContributionBase.php b/CRM/Contribute/Form/ContributionBase.php index c31e6ee9af..902e73fdea 100644 --- a/CRM/Contribute/Form/ContributionBase.php +++ b/CRM/Contribute/Form/ContributionBase.php @@ -68,7 +68,10 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form { /** * Does this form support a separate membership payment + * * @var bool + * + * @deprecated use $this->isSeparateMembershipPayment() function. */ protected $_separateMembershipPayment; @@ -1259,4 +1262,13 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form { return $this->_membershipBlock; } + /** + * Is the contribution page configured for 2 payments, one being membership & one not. + * + * @return bool + */ + protected function isSeparateMembershipPayment(): bool { + return $this->getMembershipBlock() && $this->getMembershipBlock()['is_separate_payment']; + } + } diff --git a/tests/phpunit/CRM/Contribute/Form/Contribution/ConfirmTest.php b/tests/phpunit/CRM/Contribute/Form/Contribution/ConfirmTest.php index d6c4b91e36..487e142e4a 100644 --- a/tests/phpunit/CRM/Contribute/Form/Contribution/ConfirmTest.php +++ b/tests/phpunit/CRM/Contribute/Form/Contribution/ConfirmTest.php @@ -9,6 +9,8 @@ +--------------------------------------------------------------------+ */ +use Civi\Api4\PriceSetEntity; + /** * Test APIv3 civicrm_contribute_* functions * @@ -18,10 +20,10 @@ */ class CRM_Contribute_Form_Contribution_ConfirmTest extends CiviUnitTestCase { + use CRMTraits_Financial_PriceSetTrait; + /** * Clean up DB. - * - * @throws \CRM_Core_Exception */ public function tearDown(): void { $this->quickCleanUpFinancialEntities(); @@ -36,7 +38,7 @@ class CRM_Contribute_Form_Contribution_ConfirmTest extends CiviUnitTestCase { */ public function testPayNowPayment(): void { $individualID = $this->individualCreate(); - $paymentProcessorID = $this->paymentProcessorCreate(['payment_processor_type_id' => 'Dummy']); + $paymentProcessorID = $this->paymentProcessorCreate(['payment_processor_type_id' => 'Dummy', 'is_test' => FALSE]); CRM_Core_Config::singleton()->userPermissionClass->permissions = []; // create a contribution page which is later used to make pay-later contribution @@ -57,45 +59,42 @@ class CRM_Contribute_Form_Contribution_ConfirmTest extends CiviUnitTestCase { $contributionPageID2 = $this->createContributionPage(['payment_processor' => $paymentProcessorID]); /** @var CRM_Contribute_Form_Contribution_Confirm $form */ - $form = $this->getFormObject('CRM_Contribute_Form_Contribution_Confirm'); - $form->_id = $contributionPageID2; - - $form->_paymentProcessor = [ - 'id' => $paymentProcessorID, - 'billing_mode' => CRM_Core_Payment::BILLING_MODE_FORM, - 'object' => Civi\Payment\System::singleton()->getById($paymentProcessorID), - 'is_recur' => FALSE, - 'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Credit card'), - ]; - $form->_values = [ - 'id' => $contributionPageID2, - ]; - $form->_params = [ + $_REQUEST['id'] = $contributionPageID2; + $form = $this->getFormObject('CRM_Contribute_Form_Contribution_Confirm', [ 'contribution_id' => $contribution['id'], 'credit_card_number' => 4111111111111111, 'cvv2' => 234, 'credit_card_exp_date' => [ 'M' => 2, - 'Y' => CRM_Utils_Time::date('Y') + 1, + 'Y' => (int) (CRM_Utils_Time::date('Y')) + 1, ], + $this->getPriceFieldLabelForContributionPage($contributionPageID2) => 100, 'credit_card_type' => 'Visa', 'email-5' => 'test@test.com', - 'total_amount' => 100.00, 'payment_processor_id' => $paymentProcessorID, - 'amount' => 100, - 'tax_amount' => 0.00, 'year' => 2021, 'month' => 2, 'currencyID' => 'USD', 'is_pay_later' => 0, - 'invoiceID' => '6e443672a9bb2198cc12f076aed70e7a', 'is_quick_config' => 1, 'description' => $contribution['values'][$contribution['id']]['source'], 'skipLineItem' => 0, 'frequency_interval' => 1, 'frequency_unit' => 'month', - ]; + ]); + $form->_paymentProcessor = [ + 'id' => $paymentProcessorID, + 'billing_mode' => CRM_Core_Payment::BILLING_MODE_FORM, + 'object' => Civi\Payment\System::singleton()->getById($paymentProcessorID), + 'is_recur' => FALSE, + 'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Credit card'), + ]; + $form->preProcess(); + $form->buildQuickForm(); + // Hack cos we are not going via postProcess (although we should fix the test to + // do that). + $form->_params['amount'] = 100; $processConfirmResult = $form->processConfirm( $form->_params, $individualID, @@ -186,16 +185,64 @@ class CRM_Contribute_Form_Contribution_ConfirmTest extends CiviUnitTestCase { ]); $this->assertEquals([$organizationID], $activity['target_contact_id']); $this->assertEquals($individualID, $activity['source_contact_id']); + $assignedVariables = $form->get_template_vars(); + $this->assertFalse($assignedVariables['is_separate_payment']); } /** + * Test the confirm form with a separate membership payment configured. + */ + public function testSeparatePaymentConfirm(): void { + $paymentProcessorID = $this->paymentProcessorCreate(['payment_processor_type_id' => 'Dummy', 'is_test' => FALSE]); + $contributionPageID = $this->createContributionPage(['payment_processor' => $paymentProcessorID]); + $this->setUpMembershipBlockPriceSet(['minimum_fee' => 100]); + $this->callAPISuccess('membership_block', 'create', [ + 'entity_id' => $contributionPageID, + 'entity_table' => 'civicrm_contribution_page', + 'is_required' => TRUE, + 'is_active' => TRUE, + 'is_separate_payment' => TRUE, + 'membership_type_default' => $this->ids['MembershipType'], + ]); + /** @var CRM_Contribute_Form_Contribution_Confirm $form */ + $_REQUEST['id'] = $contributionPageID; + $form = $this->getFormObject('CRM_Contribute_Form_Contribution_Confirm', [ + 'credit_card_number' => 4111111111111111, + 'cvv2' => 234, + 'credit_card_exp_date' => [ + 'M' => 2, + 'Y' => (int) (CRM_Utils_Time::date('Y')) + 1, + ], + $this->getPriceFieldLabelForContributionPage($contributionPageID) => 100, + 'priceSetId' => $this->ids['PriceSet']['contribution_page' . $contributionPageID], + 'credit_card_type' => 'Visa', + 'email-5' => 'test@test.com', + 'payment_processor_id' => $paymentProcessorID, + 'year' => 2021, + 'month' => 2, + ]); + // @todo - the way amount is handled is crazy so we have to set here + // but it should be calculated from submit variables. + $form->set('amount', 100); + $form->preProcess(); + $form->buildQuickForm(); + $form->postProcess(); + $assignedVariables = $form->get_template_vars(); + $this->assertTrue($assignedVariables['is_separate_payment']); + } + + /** + * Create a basic contribution page. + * * @param array $params * - * @return mixed - * @throws \CRM_Core_Exception + * @return int + * + * @noinspection PhpDocMissingThrowsInspection + * @noinspection PhpUnhandledExceptionInspection */ protected function createContributionPage(array $params): int { - return (int) $this->callAPISuccess('ContributionPage', 'create', array_merge([ + $contributionPageID = (int) $this->callAPISuccess('ContributionPage', 'create', array_merge([ 'title' => 'Test Contribution Page', 'financial_type_id' => 'Campaign Contribution', 'currency' => 'USD', @@ -205,6 +252,12 @@ class CRM_Contribute_Form_Contribution_ConfirmTest extends CiviUnitTestCase { 'min_amount' => 20, 'max_amount' => 2000, ], $params))['id']; + PriceSetEntity::create(FALSE)->setValues([ + 'entity_table' => 'civicrm_contribution_page', + 'entity_id' => $contributionPageID, + 'price_set_id:name' => 'default_contribution_amount', + ])->execute(); + return $contributionPageID; } } diff --git a/tests/phpunit/CRM/Contribute/Form/ContributionTest.php b/tests/phpunit/CRM/Contribute/Form/ContributionTest.php index eb3f8a2580..84f322d1c2 100644 --- a/tests/phpunit/CRM/Contribute/Form/ContributionTest.php +++ b/tests/phpunit/CRM/Contribute/Form/ContributionTest.php @@ -9,6 +9,7 @@ +--------------------------------------------------------------------+ */ +use Civi\Api4\MembershipBlock; use Civi\Api4\PriceField; use Civi\Api4\PriceSet; @@ -1635,6 +1636,11 @@ Paid By: Check', 'entity_table' => 'civicrm_contribution_page', 'entity_id' => $contribPage1, ]); + MembershipBlock::create(FALSE)->setValues([ + 'entity_id' => $contribPage1, + 'entity_table' => 'civicrm_contribution_page', + 'is_separate_payment' => FALSE, + ])->execute(); $form = new CRM_Contribute_Form_Contribution_Confirm(); $form->_params = [ @@ -1672,9 +1678,9 @@ Paid By: Check', /** * Test non-membership donation on a contribution page - * using membership priceset. + * using membership PriceSet. */ - public function testDonationOnMembershipPagePriceset() { + public function testDonationOnMembershipPagePriceSet(): void { $contactID = $this->individualCreate(); $this->createPriceSetWithPage(); $form = new CRM_Contribute_Form_Contribution_Confirm(); @@ -1697,7 +1703,6 @@ Paid By: Check', 'amount' => 10, 'tax_amount' => NULL, 'is_pay_later' => 1, - 'is_quick_config' => 1, ]; $form->submit($form->_params); diff --git a/tests/phpunit/CRMTraits/Financial/PriceSetTrait.php b/tests/phpunit/CRMTraits/Financial/PriceSetTrait.php index d40ba989cf..b7ee9194d0 100644 --- a/tests/phpunit/CRMTraits/Financial/PriceSetTrait.php +++ b/tests/phpunit/CRMTraits/Financial/PriceSetTrait.php @@ -9,7 +9,9 @@ +--------------------------------------------------------------------+ */ +use Civi\Api4\PriceField; use Civi\Api4\PriceSet; +use Civi\Api4\PriceSetEntity; /** * Trait PriceSetTrait @@ -29,6 +31,26 @@ trait CRMTraits_Financial_PriceSetTrait { return $this->ids['PriceSet'][$key]; } + /** + * Get the appropriate price field label for the given contribution page. + * + * This works for quick config pages with only one option. + * + * @return string + * + * @noinspection PhpUnhandledExceptionInspection + * @noinspection PhpDocMissingThrowsInspection + */ + protected function getPriceFieldLabelForContributionPage($contributionPageID): string { + $this->ids['PriceSet']['contribution_page' . $contributionPageID] = (int) PriceSetEntity::get(FALSE) + ->addWhere('entity_id', '=', $contributionPageID) + ->addWhere('entity_table', '=', 'civicrm_contribution_page') + ->addSelect('price_set_id')->execute()->first()['price_set_id']; + $priceFieldID = PriceField::get(FALSE)->addWhere('price_set_id', '=', $this->ids['PriceSet']['contribution_page' . $contributionPageID]) + ->addSelect('id')->execute()->first()['id']; + return 'price_' . $priceFieldID; + } + /** * Get the created price field id. * @@ -123,7 +145,8 @@ trait CRMTraits_Financial_PriceSetTrait { * * @param array $membershipTypeParams * - * @throws \CRM_Core_Exception + * @noinspection PhpDocMissingThrowsInspection + * @noinspection PhpUnhandledExceptionInspection */ protected function setUpMembershipBlockPriceSet(array $membershipTypeParams = []): void { $this->ids['PriceSet']['membership_block'] = PriceSet::create(FALSE) diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index 47fba04949..249da5f932 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -34,6 +34,7 @@ use Civi\Api4\Event; use Civi\Api4\FinancialAccount; use Civi\Api4\FinancialType; use Civi\Api4\LineItem; +use Civi\Api4\MembershipBlock; use Civi\Api4\MembershipType; use Civi\Api4\OptionGroup; use Civi\Api4\Phone; @@ -3001,7 +3002,7 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase { */ public function createPriceSetWithPage($entity = NULL, $params = []) { $membershipTypeID = $this->membershipTypeCreate(['name' => 'Special']); - $contributionPageResult = $this->callAPISuccess('contribution_page', 'create', [ + $contributionPageID = $this->callAPISuccess('contribution_page', 'create', [ 'title' => 'Test Contribution Page', 'financial_type_id' => 1, 'currency' => 'NZD', @@ -3009,7 +3010,7 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase { 'is_pay_later' => 1, 'is_monetary' => TRUE, 'is_email_receipt' => FALSE, - ]); + ])['id']; $priceSet = $this->callAPISuccess('price_set', 'create', [ 'is_quick_config' => 0, 'extends' => 'CiviMember', @@ -3018,7 +3019,7 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase { ]); $priceSetID = $priceSet['id']; - CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID); + CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPageID, $priceSetID); $priceField = $this->callAPISuccess('price_field', 'create', [ 'price_set_id' => $priceSetID, 'label' => 'Goat Breed', @@ -3052,10 +3053,15 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase { 'amount' => 10, 'financial_type_id' => 'Donation', ]); + MembershipBlock::create(FALSE)->setValues([ + 'entity_id' => $contributionPageID, + 'entity_table' => 'civicrm_contribution_page', + 'is_separate_payment' => FALSE, + ])->execute(); $this->_ids['price_field_value']['cont'] = $priceFieldValue['id']; $this->_ids['price_set'] = $priceSetID; - $this->_ids['contribution_page'] = $contributionPageResult['id']; + $this->_ids['contribution_page'] = $contributionPageID; $this->_ids['price_field'] = [$priceField['id']]; $this->_ids['membership_type'] = $membershipTypeID; @@ -3154,6 +3160,13 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase { $form->controller = new CRM_Event_Controller_Registration(); break; + case 'CRM_Contribute_Form_Contribution_Confirm': + $form->controller = new CRM_Contribute_Controller_Contribution(); + $form->controller->setStateMachine(new CRM_Contribute_StateMachine_Contribution($form->controller)); + // The submitted values are on the Main form. + $_SESSION['_' . $form->controller->_name . '_container']['values']['Main'] = $formValues; + return $form; + case 'CRM_Contact_Import_Form_DataSource': case 'CRM_Contact_Import_Form_MapField': case 'CRM_Contact_Import_Form_Preview': -- 2.25.1