Skip to content

Commit

Permalink
Merge pull request #22825 from MegaphoneJon/membership-41
Browse files Browse the repository at this point in the history
get membership type ID and number of terms from price_x fields
  • Loading branch information
monishdeb authored Mar 15, 2022
2 parents ecfb333 + c656704 commit 2eab448
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 80 deletions.
55 changes: 24 additions & 31 deletions CRM/Contribute/Form/ContributionBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -1138,40 +1138,33 @@ public function cancelRecurring() {
* Arguably the form should start to build $this->_params in the pre-process main page & use that array consistently throughout.
*/
protected function setRecurringMembershipParams() {
$selectedMembershipTypeID = $this->_params['selectMembership'] ?? NULL;
if ($selectedMembershipTypeID) {
// @todo the price_x fields will ALWAYS allow us to determine the membership - so we should ignore
// 'selectMembership' and calculate from the price_x fields so we have one method that always works
// this is lazy & only catches when selectMembership is set, but the worst of all worlds would be to fix
// this with an else (calculate for price set).
$membershipTypes = CRM_Price_BAO_PriceSet::getMembershipTypesFromPriceSet($this->_priceSetId);
if (in_array($selectedMembershipTypeID, $membershipTypes['autorenew_required'])
|| (in_array($selectedMembershipTypeID, $membershipTypes['autorenew_optional']) &&
!empty($this->_params['is_recur']))
) {
$this->_params['auto_renew'] = TRUE;
}
$priceFieldId = array_key_first($this->_values['fee']);
// Why is this an array in CRM_Contribute_Form_Contribution_Main::submit and a string in CRM_Contribute_Form_Contribution_Confirm::preProcess()?
if (is_array($this->_params["price_{$priceFieldId}"])) {
$priceFieldValue = array_key_first($this->_params["price_{$priceFieldId}"]);
}
else {
$priceFieldValue = $this->_params["price_{$priceFieldId}"];
}
$selectedMembershipTypeID = $this->_values['fee'][$priceFieldId]['options'][$priceFieldValue]['membership_type_id'] ?? NULL;
if (!$selectedMembershipTypeID) {
return;
}
if ((!empty($this->_params['selectMembership']) || !empty($this->_params['priceSetId']))
&& !empty($this->_paymentProcessor['is_recur']) &&
!empty($this->_params['auto_renew'])
&& empty($this->_params['is_recur']) && empty($this->_params['frequency_interval'])
) {

$membershipTypes = CRM_Price_BAO_PriceSet::getMembershipTypesFromPriceSet($this->_priceSetId);
if (in_array($selectedMembershipTypeID, $membershipTypes['autorenew_required'])
|| (in_array($selectedMembershipTypeID, $membershipTypes['autorenew_optional']) &&
!empty($this->_params['is_recur']))
&& !empty($this->_paymentProcessor['is_recur'])
) {
$this->_params['auto_renew'] = TRUE;
$this->_params['is_recur'] = $this->_values['is_recur'] = 1;
// check if price set is not quick config
if (!empty($this->_params['priceSetId']) && !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_params['priceSetId'], 'is_quick_config')) {
list($this->_params['frequency_interval'], $this->_params['frequency_unit']) = CRM_Price_BAO_PriceSet::getRecurDetails($this->_params['priceSetId']);
}
else {
// FIXME: set interval and unit based on selected membership type
$this->_params['frequency_interval'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
$this->_params['selectMembership'], 'duration_interval'
);
$this->_params['frequency_unit'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
$this->_params['selectMembership'], 'duration_unit'
);
}
$membershipTypeDetails = \Civi\Api4\MembershipType::get(FALSE)
->addWhere('id', '=', $selectedMembershipTypeID)
->execute()
->first();
$this->_params['frequency_interval'] = $this->_params['frequency_interval'] ?? $this->_values['fee'][$priceFieldId]['options'][$priceFieldValue]['membership_num_terms'];
$this->_params['frequency_unit'] = $this->_params['frequency_unit'] ?? $membershipTypeDetails['duration_unit'];
}
}

Expand Down
22 changes: 0 additions & 22 deletions CRM/Price/BAO/PriceSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -1247,28 +1247,6 @@ public static function checkAutoRenewForPriceSet($priceSetId) {
return $autoRenewOption;
}

/**
* Retrieve auto renew frequency and interval.
*
* @param int $priceSetId
* Price set id.
*
* @return array
* associate array of frequency interval and unit
*/
public static function getRecurDetails($priceSetId) {
$query = 'SELECT mt.duration_interval, mt.duration_unit
FROM civicrm_price_field_value pfv
INNER JOIN civicrm_membership_type mt ON pfv.membership_type_id = mt.id
INNER JOIN civicrm_price_field pf ON pfv.price_field_id = pf.id
WHERE pf.price_set_id = %1 LIMIT 1';

$params = [1 => [$priceSetId, 'Integer']];
$dao = CRM_Core_DAO::executeQuery($query, $params);
$dao->fetch();
return [$dao->duration_interval, $dao->duration_unit];
}

/**
* @return object
*/
Expand Down
96 changes: 75 additions & 21 deletions tests/phpunit/CRM/Contribute/Form/Contribution/MainTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,24 @@
*/
class CRM_Contribute_Form_Contribution_MainTest extends CiviUnitTestCase {

/**
* The id of the contribution page.
* @var int
*/
private int $contributionPageId;

/**
* The id of the contribution page's payment processor.
* @var int
*/
private int $paymentProcessorId;

/**
* The price set of the contribution page.
* @var int
*/
private int $priceSetId;

/**
* Clean up DB.
*/
Expand All @@ -26,53 +44,84 @@ public function tearDown(): void {
parent::tearDown();
}

/**
* Given a membership type ID, return the price field value.
*/
private function getPriceFieldValue($membershipTypeId) {
return $this->callAPISuccessGetValue('PriceFieldValue', ['membership_type_id' => $membershipTypeId, 'return' => 'id']);
}

/**
* Establish a standard list of submit params to more accurately test the submission.
*/
private function getSubmitParams() {
return [
'id' => $this->contributionPageId,
'amount' => 80,
'first_name' => 'Billy',
'last_name' => 'Gruff',
'email' => 'billy@goat.gruff',
'payment_processor_id' => $this->paymentProcessorId,
'credit_card_number' => '4111111111111111',
'credit_card_type' => 'Visa',
'credit_card_exp_date' => ['M' => 9, 'Y' => 2040],
'cvv2' => 123,
'auto_renew' => 1,
'priceSetId' => $this->priceSetId,
];
}

/**
* Test that the membership is set to recurring if the membership type is always autorenew.
*/
public function testSetRecurFunction() {
$membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 2, 'minimum_fee' => 80]);
$form = $this->getContributionForm();
$form->testSubmit([
'selectMembership' => $membershipTypeID,
]);
$priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
$form->testSubmit(array_merge($this->getSubmitParams(), [
'price_' . $this->priceSetId => $priceFieldValueId,
]));
$this->assertEquals(1, $form->_params['is_recur']);
}

/**
* Test that the membership is set to recurring if the membership type is always autorenew.
* Test that the membership is set to recurring if the membership type is optionally autorenew and is_recur is true.
*/
public function testSetRecurFunctionOptionalYes() {
$membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 1, 'minimum_fee' => 80]);
$form = $this->getContributionForm();
$form->testSubmit([
'selectMembership' => $membershipTypeID,
$priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
$form->testSubmit(array_merge($this->getSubmitParams(), [
'price_' . $this->priceSetId => $priceFieldValueId,
'is_recur' => 1,
]);
]));
$this->assertEquals(1, $form->_params['is_recur']);
}

/**
* Test that the membership is set to recurring if the membership type is always autorenew.
* Test that the membership is not set to recurring if the membership type is optionally autorenew and is_recur is false.
*/
public function testSetRecurFunctionOptionalNo() {
$membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 1, 'minimum_fee' => 80]);
$form = $this->getContributionForm();
$form->testSubmit([
'selectMembership' => $membershipTypeID,
$priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
$form->testSubmit(array_merge($this->getSubmitParams(), [
'price_' . $this->priceSetId => $priceFieldValueId,
'is_recur' => 0,
]);
]));
$this->assertEquals(0, $form->_params['is_recur']);
}

/**
* Test that the membership is set to recurring if the membership type is always autorenew.
* Test that the membership doesn't have an "is_recur" key if the membership type can never autorenew.
*/
public function testSetRecurFunctionNotAvailable() {
$membershipTypeID = $this->membershipTypeCreate(['auto_renew' => 0, 'minimum_fee' => 80]);
$form = $this->getContributionForm();
$form->testSubmit([
'selectMembership' => $membershipTypeID,
]);
$priceFieldValueId = $this->getPriceFieldValue($membershipTypeID);
$form->testSubmit(array_merge($this->getSubmitParams(), [
'price_' . $this->priceSetId => $priceFieldValueId,
]));
$this->assertArrayNotHasKey('is_recur', $form->_params);
}

Expand All @@ -82,11 +131,16 @@ public function testSetRecurFunctionNotAvailable() {
* @return \CRM_Contribute_Form_Contribution_Main
*/
protected function getContributionForm($params = []) {
$params['priceSetID'] = $params['priceSetID'] ?? $this->callAPISuccessGetValue('PriceSet', [
$this->priceSetId = $params['priceSetID'] ?? $this->callAPISuccessGetValue('PriceSet', [
'name' => 'default_membership_type_amount',
'return' => 'id',
]);

$paymentProcessor = $this->paymentProcessorCreate([
'payment_processor_type_id' => 'Dummy',
'is_test' => 0,
]);

$contributionPageParams = (array_merge($params, [
'currency' => 'NZD',
'goal_amount' => 6000,
Expand All @@ -95,20 +149,20 @@ protected function getContributionForm($params = []) {
'pay_later_text' => 'Front up',
'pay_later_receipt' => 'Ta',
'is_email_receipt' => 1,
'payment_processor' => $this->paymentProcessorCreate([
'payment_processor_type_id' => 'Dummy',
'is_test' => 0,
]),
'payment_processor' => $paymentProcessor,
'amount_block_is_active' => 1,
]));

/** @var \CRM_Contribute_Form_Contribution_Main $form */
$form = $this->getFormObject('CRM_Contribute_Form_Contribution_Main');
$contributionPage = reset($this->contributionPageCreate($contributionPageParams)['values']);
$form->set('id', $contributionPage['id']);
CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPage['id'], $params['priceSetID']);
CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPage['id'], $this->priceSetId);
$form->preProcess();
$form->buildQuickForm();
// Need these values to create more realistic submit params (in getSubmitParams).
$this->paymentProcessorId = $paymentProcessor;
$this->contributionPageId = (int) $contributionPage['id'];
return $form;
}

Expand Down
37 changes: 31 additions & 6 deletions tests/phpunit/api/v3/ContributionPageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1406,12 +1406,18 @@ public function setUpMultiIntervalMembershipContributionPage(): void {
$contributionPage = $this->callAPISuccess($this->_entity, 'create', $this->params);
$this->_ids['contribution_page'] = $contributionPage['id'];

$this->ids['MembershipType'] = $this->membershipTypeCreate([
$this->ids['MembershipTypeMonth'] = $this->membershipTypeCreate([
// force auto-renew
'auto_renew' => 2,
'duration_unit' => 'month',
]);

$this->ids['MembershipTypeYear'] = $this->membershipTypeCreate([
// force auto-renew
'auto_renew' => 2,
'duration_unit' => 'year',
]);

$priceSet = $this->callAPISuccess('PriceSet', 'create', [
'is_quick_config' => 0,
'extends' => 'CiviMember',
Expand All @@ -1433,18 +1439,29 @@ public function setUpMultiIntervalMembershipContributionPage(): void {
'label' => 'CRM-21177 - Monthly',
'amount' => 20,
'membership_num_terms' => 1,
'membership_type_id' => $this->ids['MembershipType'],
'membership_type_id' => $this->ids['MembershipTypeMonth'],
'price_field_id' => $this->_ids['price_field'],
'financial_type_id' => 'Member Dues',
]);
$this->_ids['price_field_value_monthly'] = $priceFieldValueMonthly['id'];

$priceFieldValue12Months = $this->callAPISuccess('price_field_value', 'create', [
'name' => 'CRM-21177_12_Months',
'label' => 'CRM-21177 - 12 Months',
'amount' => 200,
'membership_num_terms' => 12,
'membership_type_id' => $this->ids['MembershipTypeMonth'],
'price_field_id' => $this->_ids['price_field'],
'financial_type_id' => 'Member Dues',
]);
$this->_ids['price_field_value_12_months'] = $priceFieldValue12Months['id'];

$priceFieldValueYearly = $this->callAPISuccess('price_field_value', 'create', [
'name' => 'CRM-21177_Yearly',
'label' => 'CRM-21177 - Yearly',
'amount' => 200,
'membership_num_terms' => 12,
'membership_type_id' => $this->ids['MembershipType'],
'membership_num_terms' => 1,
'membership_type_id' => $this->ids['MembershipTypeYear'],
'price_field_id' => $this->_ids['price_field'],
'financial_type_id' => 'Member Dues',
]);
Expand All @@ -1458,7 +1475,7 @@ public function setUpMultiIntervalMembershipContributionPage(): void {
'is_required' => TRUE,
'is_separate_payment' => FALSE,
'is_active' => TRUE,
'membership_type_default' => $this->ids['MembershipType'],
'membership_type_default' => $this->ids['MembershipTypeMonth'],
]);
}

Expand Down Expand Up @@ -1488,13 +1505,21 @@ public function testSubmitMultiIntervalMembershipContributionPage(): void {
$submitParams['price_' . $this->_ids['price_field']] = $this->_ids['price_field_value_yearly'];
$this->callAPISuccess('contribution_page', 'submit', $submitParams);

$submitParams['price_' . $this->_ids['price_field']] = $this->_ids['price_field_value_12_months'];
$this->callAPISuccess('contribution_page', 'submit', $submitParams);

$contribution = $this->callAPISuccess('Contribution', 'get', [
'contribution_page_id' => $this->_ids['contribution_page'],
'sequential' => 1,
'api.ContributionRecur.getsingle' => [],
]);
$this->assertEquals(1, $contribution['values'][0]['api.ContributionRecur.getsingle']['frequency_interval']);
//$this->assertEquals(12, $contribution['values'][1]['api.ContributionRecur.getsingle']['frequency_interval']);
$this->assertEquals(1, $contribution['values'][1]['api.ContributionRecur.getsingle']['frequency_interval']);
$this->assertEquals(12, $contribution['values'][2]['api.ContributionRecur.getsingle']['frequency_interval']);

$this->assertEquals('month', $contribution['values'][0]['api.ContributionRecur.getsingle']['frequency_unit']);
$this->assertEquals('year', $contribution['values'][1]['api.ContributionRecur.getsingle']['frequency_unit']);
$this->assertEquals('month', $contribution['values'][2]['api.ContributionRecur.getsingle']['frequency_unit']);
}

/**
Expand Down

0 comments on commit 2eab448

Please sign in to comment.