* 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'];
}
}
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
*/
*/
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.
*/
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);
}
* @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,
'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,
]));
$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;
}
$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',
'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',
]);
'is_required' => TRUE,
'is_separate_payment' => FALSE,
'is_active' => TRUE,
- 'membership_type_default' => $this->ids['MembershipType'],
+ 'membership_type_default' => $this->ids['MembershipTypeMonth'],
]);
}
$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']);
}
/**