diff --git a/CRM/Member/Form/Membership.php b/CRM/Member/Form/Membership.php index 3169844fdc0b..aecab9df5b07 100644 --- a/CRM/Member/Form/Membership.php +++ b/CRM/Member/Form/Membership.php @@ -1162,6 +1162,12 @@ public function submit() { $lineItem = [$this->_priceSetId => []]; + // BEGIN Fix for dev/core/issues/860 + // Prepare fee block and call buildAmount hook - based on CRM_Price_BAO_PriceSet::buildPriceSet(). + CRM_Price_BAO_PriceSet::applyACLFinancialTypeStatusToFeeBlock($this->_priceSet['fields']); + CRM_Utils_Hook::buildAmount('membership', $this, $this->_priceSet['fields']); + // END Fix for dev/core/issues/860 + CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], $formValues, $lineItem[$this->_priceSetId], NULL, $this->_priceSetId); diff --git a/CRM/Price/BAO/PriceSet.php b/CRM/Price/BAO/PriceSet.php index c5b7caaad661..68ae0a0d4eaa 100644 --- a/CRM/Price/BAO/PriceSet.php +++ b/CRM/Price/BAO/PriceSet.php @@ -1008,19 +1008,9 @@ public static function buildPriceSet(&$form) { else { $feeBlock = &$form->_priceSet['fields']; } - if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) { - foreach ($feeBlock as $key => $value) { - foreach ($value['options'] as $k => $options) { - if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($options['financial_type_id']))) { - unset($feeBlock[$key]['options'][$k]); - } - } - if (empty($feeBlock[$key]['options'])) { - unset($feeBlock[$key]); - } - } - } - // call the hook. + + self::applyACLFinancialTypeStatusToFeeBlock($feeBlock); + // Call the buildAmount hook. CRM_Utils_Hook::buildAmount($component, $form, $feeBlock); // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions @@ -1074,6 +1064,29 @@ public static function buildPriceSet(&$form) { } } + /** + * Apply ACLs on Financial Type to the price options in a fee block. + * + * @param array $feeBlock + * Fee block: array of price fields. + * + * @return void + */ + public static function applyACLFinancialTypeStatusToFeeBlock(&$feeBlock) { + if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) { + foreach ($feeBlock as $key => $value) { + foreach ($value['options'] as $k => $options) { + if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($options['financial_type_id']))) { + unset($feeBlock[$key]['options'][$k]); + } + } + if (empty($feeBlock[$key]['options'])) { + unset($feeBlock[$key]); + } + } + } + } + /** * Check the current Membership having end date null. * diff --git a/tests/phpunit/CRM/Member/Form/MembershipTest.php b/tests/phpunit/CRM/Member/Form/MembershipTest.php index c42b52a06f5d..d70cee241327 100644 --- a/tests/phpunit/CRM/Member/Form/MembershipTest.php +++ b/tests/phpunit/CRM/Member/Form/MembershipTest.php @@ -1085,6 +1085,57 @@ public function testTwoInheritedMembershipsViaPriceSetInBackend() { $this->assertEquals(1, $contributionResultAfterRelationshipDelete['count'], "Contribution has been wrongly deleted."); } + /** + * dev/core/issues/860: + * Test creating two memberships via price set in the back end with a discount, + * checking that the line items have correct amounts. + */ + public function testTwoMembershipsViaPriceSetInBackendWithDiscount() { + // Register buildAmount hook to apply discount. + $this->hookClass->setHook('civicrm_buildAmount', [$this, 'buildAmountMembershipDiscount']); + + // Create two memberships for individual $this->_individualId, via a price set in the back end. + $this->createTwoMembershipsViaPriceSetInBackEnd($this->_individualId); + $contribution = $this->callAPISuccessGetSingle('Contribution', [ + 'contact_id' => $this->_individualId, + ]); + // Note: we can't check for the contribution total being discounted, because the total is set + // when the contribution is created via $form->testSubmit(), but buildAmount isn't called + // until testSubmit() runs. Fixing that might involve making testSubmit() more sophisticated, + // or just hacking total_amount for this case. + + $lineItemResult = $this->callAPISuccess('LineItem', 'get', [ + 'contribution_id' => $contribution['id'], + ]); + $this->assertEquals(2, $lineItemResult['count']); + $discountedItems = 0; + foreach ($lineItemResult['values'] as $lineItem) { + if (CRM_Utils_String::startsWith($lineItem['label'], 'Long Haired Goat')) { + $this->assertEquals(15.0, $lineItem['line_total']); + $this->assertEquals('Long Haired Goat - one leg free!', $lineItem['label']); + $discountedItems++; + } + } + $this->assertEquals(1, $discountedItems); + } + + /** + * Implements hook_civicrm_buildAmount() for testTwoMembershipsViaPriceSetInBackendWithDiscount(). + */ + public function buildAmountMembershipDiscount($pageType, &$form, &$amount) { + foreach ($amount as $id => $priceField) { + if (is_array($priceField['options'])) { + foreach ($priceField['options'] as $optionId => $option) { + if ($option['membership_type_id'] == 15) { + // Long Haired Goat membership discount. + $amount[$id]['options'][$optionId]['amount'] = $option['amount'] * 0.75; + $amount[$id]['options'][$optionId]['label'] = $option['label'] . ' - one leg free!'; + } + } + } + } + } + /** * Get a membership form object. *