From 8f48ed999ceac477988f1f93ade42b623fd26672 Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Wed, 20 Dec 2023 10:56:52 +1300 Subject: [PATCH] Fix autorenew checkbox with memberships --- CRM/Contribute/Form/Contribution/Confirm.php | 1 + CRM/Contribute/Form/Contribution/Main.php | 94 +++++++++++++++---- CRM/Contribute/Form/Contribution/ThankYou.php | 1 + CRM/Contribute/Form/ContributionBase.php | 17 ++++ CRM/Financial/BAO/Order.php | 13 ++- .../Contribute/Form/Contribution/Confirm.tpl | 6 +- .../Form/Contribution/MainMembershipBlock.tpl | 27 ++---- .../Form/Contribution/MembershipBlock.tpl | 4 +- .../Contribute/Form/Contribution/ThankYou.tpl | 2 +- templates/CRM/Price/Form/PriceSet.tpl | 26 +++-- 10 files changed, 125 insertions(+), 66 deletions(-) diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php index 08c86427bd..ab9987f216 100644 --- a/CRM/Contribute/Form/Contribution/Confirm.php +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -750,6 +750,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr $this->assign('membershipBlock', $this->_membershipBlock); $this->assign('showRadio', FALSE); + $this->assignTotalAmounts(); $this->assign('membershipTypes', $membershipTypes); $this->assign('autoRenewMembershipTypeOptions', json_encode($autoRenewMembershipTypeOptions)); //give preference to user submitted auto_renew value. diff --git a/CRM/Contribute/Form/Contribution/Main.php b/CRM/Contribute/Form/Contribution/Main.php index b3120cf913..14eea10c16 100644 --- a/CRM/Contribute/Form/Contribution/Main.php +++ b/CRM/Contribute/Form/Contribution/Main.php @@ -617,17 +617,18 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu * * @throws \CRM_Core_Exception */ - private function buildMembershipBlock() { + private function buildMembershipBlock(): ?bool { $cid = $this->_membershipContactID; $separateMembershipPayment = FALSE; $this->addOptionalQuickFormElement('auto_renew'); + $this->addExpectedSmartyVariable('renewal_mode'); if ($this->_membershipBlock) { $membershipTypeIds = $membershipTypes = $radio = $radioOptAttrs = []; // This is always true if this line is reachable - remove along with the upcoming if. $membershipPriceset = TRUE; - $allowAutoRenewMembership = $autoRenewOption = FALSE; + $allowAutoRenewMembership = FALSE; $autoRenewMembershipTypeOptions = []; $separateMembershipPayment = $this->_membershipBlock['is_separate_payment'] ?? NULL; @@ -651,30 +652,17 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu $this->_membershipTypeValues = $membershipTypeValues; $endDate = NULL; - // Check if we support auto-renew on this contribution page - // FIXME: If any of the payment processors do NOT support recurring you cannot setup an - // auto-renew payment even if that processor is not selected. - $allowAutoRenewOpt = TRUE; - if (is_array($this->_paymentProcessors)) { - foreach ($this->_paymentProcessors as $id => $val) { - if ($id && !$val['is_recur']) { - $allowAutoRenewOpt = FALSE; - } - } - } + $allowAutoRenewOpt = $this->isPageHasPaymentProcessorSupportForRecurring(); foreach ($membershipTypeIds as $value) { $memType = $membershipTypeValues[$value]; if ($memType['is_active']) { - + $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = $this->getConfiguredAutoRenewOptionForMembershipType($value); if ($allowAutoRenewOpt) { $javascriptMethod = ['onclick' => "return showHideAutoRenew( this.value );"]; - $isAvailableAutoRenew = $this->_membershipBlock['auto_renew'][$value] ?? 1; - $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = (int) $memType['auto_renew'] * $isAvailableAutoRenew; $allowAutoRenewMembership = TRUE; } else { $javascriptMethod = NULL; - $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = 0; } //add membership type. @@ -717,9 +705,8 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu //give preference to user submitted auto_renew value. $takeUserSubmittedAutoRenew = (!empty($_POST) || $this->isSubmitted()); $this->assign('takeUserSubmittedAutoRenew', $takeUserSubmittedAutoRenew); - + $autoRenewOption = $this->getAutoRenewOption(); // Assign autorenew option (0:hide,1:optional,2:required) so we can use it in confirmation etc. - $autoRenewOption = CRM_Price_BAO_PriceSet::checkAutoRenewForPriceSet($this->_priceSetId); $this->assign('autoRenewOption', $autoRenewOption); if ((!$this->_values['is_pay_later'] || is_array($this->_paymentProcessors)) && ($allowAutoRenewMembership || $autoRenewOption)) { @@ -1812,4 +1799,73 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu return $membershipTypeIDs; } + /** + * @return int + */ + private function getAutoRenewOption(): int { + $autoRenewOption = 0; + foreach ($this->getPriceFieldMetaData() as $field) { + foreach ($field['options'] as $option) { + if ($option['membership_type_id.auto_renew'] === 1) { + $autoRenewOption = 1; + break 2; + } + if ($option['membership_type_id.auto_renew'] === 2) { + $autoRenewOption = 2; + } + } + } + return $autoRenewOption; + } + + /** + * Get configured auto renew option. + * + * One of + * 0 = never + * 1 = optional + * 2 - always + * + * This is based on the membership type but 1 can be moved up or down by membership block configuration. + * + * @param int $membershipTypeID + * + * @return int + * @throws \CRM_Core_Exception + */ + private function getConfiguredAutoRenewOptionForMembershipType($membershipTypeID): int { + if (!$this->isPageHasPaymentProcessorSupportForRecurring()) { + return 0; + } + if (!$this->isQuickConfig()) { + return CRM_Member_BAO_MembershipType::getMembershipType($membershipTypeID)['auto_renew']; + } + $membershipTypeAutoRenewOption = CRM_Member_BAO_MembershipType::getMembershipType($membershipTypeID)['auto_renew']; + if ($membershipTypeAutoRenewOption === 2 || $membershipTypeAutoRenewOption === 0) { + // It is not possible to override never or always at the membership block leve. + return $membershipTypeAutoRenewOption; + } + // For quick config it is possible to override the give option membership type setting in the membership block. + return $this->_membershipBlock['auto_renew'][$membershipTypeID] ?? $membershipTypeAutoRenewOption; + } + + /** + * Is there payment processor support for recurring contributions on the the contribution page. + * + * As our front end js is not clever enough to deal with switching this returns FALSE + * if any configured processor will not do recurring. + * + * @return bool + */ + private function isPageHasPaymentProcessorSupportForRecurring(): bool { + if (is_array($this->_paymentProcessors)) { + foreach ($this->_paymentProcessors as $id => $val) { + if ($id && !$val['is_recur']) { + return FALSE; + } + } + } + return TRUE; + } + } diff --git a/CRM/Contribute/Form/Contribution/ThankYou.php b/CRM/Contribute/Form/Contribution/ThankYou.php index 3c3e200f3a..2a146f154c 100644 --- a/CRM/Contribute/Form/Contribution/ThankYou.php +++ b/CRM/Contribute/Form/Contribution/ThankYou.php @@ -49,6 +49,7 @@ class CRM_Contribute_Form_Contribution_ThankYou extends CRM_Contribute_Form_Cont $this->assign('thankyou_footer', CRM_Utils_Array::value('thankyou_footer', $this->_values)); $this->assign('max_reminders', CRM_Utils_Array::value('max_reminders', $this->_values)); $this->assign('initial_reminder_day', CRM_Utils_Array::value('initial_reminder_day', $this->_values)); + $this->assignTotalAmounts(); // Link (button) for users to create their own Personal Campaign page if ($linkText = CRM_PCP_BAO_PCP::getPcpBlockStatus($this->getContributionPageID(), 'contribute')) { $linkTextUrl = CRM_Utils_System::url('civicrm/contribute/campaign', diff --git a/CRM/Contribute/Form/ContributionBase.php b/CRM/Contribute/Form/ContributionBase.php index 411b01fef2..1040711c72 100644 --- a/CRM/Contribute/Form/ContributionBase.php +++ b/CRM/Contribute/Form/ContributionBase.php @@ -1526,6 +1526,23 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form { } } + /** + * Assign the total amounts for display on Confirm and ThankYou pages. + * + * These values are used in the separate payments section. + * + * @return void + * @throws \CRM_Core_Exception + */ + protected function assignTotalAmounts(): void { + // orderTotal includes both payments, if separate. + $orderTotal = $this->getOrder() ? $this->order->getTotalAmount() : 0; + $membershipTotalAmount = $this->getOrder() ? $this->order->getMembershipTotalAmount() : 0; + $this->assign('orderTotal', $orderTotal); + $this->assign('membershipTotalAmount', $membershipTotalAmount); + $this->assign('nonMembershipTotalAmount', $orderTotal - $membershipTotalAmount); + } + /** * Get the currency for the form. * diff --git a/CRM/Financial/BAO/Order.php b/CRM/Financial/BAO/Order.php index ec85b13fec..15c578b3ce 100644 --- a/CRM/Financial/BAO/Order.php +++ b/CRM/Financial/BAO/Order.php @@ -672,6 +672,7 @@ class CRM_Financial_BAO_Order { */ protected function setPriceFieldMetadata(array $metadata): void { foreach ($metadata as $index => $priceField) { + $metadata[$index]['supports_auto_renew'] = FALSE; if ($this->isExcludeExpiredFields && !$priceField['is_active']) { unset($metadata[$index]); } @@ -688,12 +689,11 @@ class CRM_Financial_BAO_Order { } elseif (!empty($option['membership_type_id'])) { $membershipType = CRM_Member_BAO_MembershipType::getMembershipType((int) $option['membership_type_id']); - $metadata[$index]['options'][$optionID]['auto_renew'] = (int) $membershipType['auto_renew']; - if ($membershipType['auto_renew'] && empty($this->priceSetMetadata['auto_renew_membership_field'])) { - // Quick form layer supports one auto-renew membership type per price set. If we - // want more for any reason we can add another array property. - $this->priceSetMetadata['auto_renew_membership_field'] = (int) $option['price_field_id']; - } + $metadata[$index]['options'][$optionID]['membership_type_id.auto_renew'] = (int) $membershipType['auto_renew']; + $metadata[$index]['supports_auto_renew'] = $membershipType['auto_renew'] ?: (bool) $membershipType['auto_renew']; + } + else { + $metadata[$index]['options'][$optionID]['membership_type_id.auto_renew'] = NULL; } } } @@ -717,7 +717,6 @@ class CRM_Financial_BAO_Order { if (empty($this->priceSetMetadata)) { $this->priceSetMetadata = CRM_Price_BAO_PriceSet::getCachedPriceSetDetail($this->getPriceSetID()); $this->priceSetMetadata['id'] = $this->getPriceSetID(); - $this->priceSetMetadata['auto_renew_membership_field'] = NULL; $this->setPriceFieldMetadata($this->priceSetMetadata['fields']); unset($this->priceSetMetadata['fields']); } diff --git a/templates/CRM/Contribute/Form/Contribution/Confirm.tpl b/templates/CRM/Contribute/Form/Contribution/Confirm.tpl index 4df6a2f8ee..1e8442f936 100644 --- a/templates/CRM/Contribute/Form/Contribution/Confirm.tpl +++ b/templates/CRM/Contribute/Form/Contribution/Confirm.tpl @@ -40,15 +40,15 @@ {elseif $is_separate_payment} {if $amount AND $minimum_fee} {$membership_name} {ts}Membership{/ts}: - {$minimum_fee|crmMoney} + {$membershipTotalAmount|crmMoney}
{ts}Additional Contribution{/ts}: - {$amount|crmMoney} + {$nonMembershipTotalAmount|crmMoney}
-------------------------------------------
{ts}Total{/ts}: - {$amount+$minimum_fee|crmMoney} + {$orderTotal|crmMoney}
{elseif $amount} {ts}Amount{/ts}: diff --git a/templates/CRM/Contribute/Form/Contribution/MainMembershipBlock.tpl b/templates/CRM/Contribute/Form/Contribution/MainMembershipBlock.tpl index 65bf96acba..c4aca65220 100644 --- a/templates/CRM/Contribute/Form/Contribution/MainMembershipBlock.tpl +++ b/templates/CRM/Contribute/Form/Contribution/MainMembershipBlock.tpl @@ -20,10 +20,10 @@ {/if} {else} - {if $membershipBlock.new_title} + {if array_key_exists('new_title', $membershipBlock) && $membershipBlock.new_title} {$membershipBlock.new_title} {/if} - {if $membershipBlock.new_text} + {if array_key_exists('new_text', $membershipBlock) && $membershipBlock.new_text}
{$membershipBlock.new_text}
@@ -52,23 +52,7 @@ {literal} {/literal} @@ -155,13 +139,16 @@ //does this page has only one membership type. var renewOptions = {/literal}{$autoRenewMembershipTypeOptions}{literal}; var currentOption = eval( "renewOptions." + 'autoRenewMembershipType_' + memTypeId ); + if (memTypeId === undefined) { + currentOption = 0; + } var autoRenew = cj('#auto_renew_section'); var autoRenewC = cj('input[name="auto_renew"]'); var forceRenew = cj("#force_renew"); var readOnly = false; var isChecked = false; - if ( currentOption == 0 ) { + if (currentOption == 0 ) { isChecked = false; forceRenew.hide(); autoRenew.hide(); diff --git a/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl b/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl index ccc677fe71..04cd616d8e 100644 --- a/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl +++ b/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl @@ -13,13 +13,13 @@ {if $membershipBlock AND $is_quick_config}
{if $renewal_mode} - {if $membershipBlock.renewal_title} + {if array_key_exists('renewal_title', $membershipBlock) && $membershipBlock.renewal_title} {$membershipBlock.renewal_title} {else} {ts}Select a Membership Renewal Level{/ts} {/if} {else} - {if $membershipBlock.new_title} + {if array_key_exists('new_title', $membershipBlock) && $membershipBlock.new_title} {$membershipBlock.new_title} {else} {ts}Select a Membership Level{/ts} diff --git a/templates/CRM/Contribute/Form/Contribution/ThankYou.tpl b/templates/CRM/Contribute/Form/Contribution/ThankYou.tpl index 684759af46..74854f2d16 100644 --- a/templates/CRM/Contribute/Form/Contribution/ThankYou.tpl +++ b/templates/CRM/Contribute/Form/Contribution/ThankYou.tpl @@ -93,7 +93,7 @@ {/if} {/if} -------------------------------------------
- {ts}Total{/ts}: {$amount+$membership_amount|crmMoney}
+ {ts}Total{/ts}: {$orderTotal|crmMoney}
{else} {if $totalTaxAmount} {ts}Tax Amount{/ts}: {$totalTaxAmount|crmMoney}
diff --git a/templates/CRM/Price/Form/PriceSet.tpl b/templates/CRM/Price/Form/PriceSet.tpl index 6f64069ee4..32503867de 100644 --- a/templates/CRM/Price/Form/PriceSet.tpl +++ b/templates/CRM/Price/Form/PriceSet.tpl @@ -95,21 +95,19 @@
{/if} - {if !empty($extends) && $extends eq "Membership"} - {if ($element.id == $priceSet.auto_renew_membership_field)} -
-
-
-
- {if $form.auto_renew} - {$form.auto_renew.html} {$form.auto_renew.label|smarty:nodefaults|purify} - {/if} -
- -
+ {if (array_key_exists('auto_renew', $form)) && !empty($extends) && $extends eq "Membership" && array_key_exists('supports_auto_renew', $element) && $element.supports_auto_renew} +
+
+
+
+ {if $form.auto_renew} + {$form.auto_renew.html} {$form.auto_renew.label|smarty:nodefaults|purify} + {/if}
- {/if} - {/if} + +
+
+ {/if}
{/if} -- 2.25.1