From 3c1e8bdd975ca082157b425b43958e8cc853fdbb Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 6 Feb 2024 18:20:15 +1300 Subject: [PATCH] dev/core#4963 Fix validation error on membership renew with auto-renew --- CRM/Contribute/Form/Contribution/Confirm.php | 13 +++-- CRM/Contribute/Form/Contribution/Main.php | 57 +++++++++++++++----- CRM/Core/Form.php | 26 ++++++--- CRM/Price/BAO/LineItem.php | 4 +- 4 files changed, 75 insertions(+), 25 deletions(-) diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php index ab9987f216..a4a59982b8 100644 --- a/CRM/Contribute/Form/Contribution/Confirm.php +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -506,6 +506,15 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr else { $this->assign('products'); } + // These 2 assigns may be overwritten in buildMembershipBlock. + // and they drive the text around reneal selection. + $this->assign('auto_renew', $this->getSubmittedValue('auto_renew')); + foreach ($this->getLineItems() as $lineItem) { + if ($lineItem['auto_renew'] ?? NULL === 2) { + $this->assign('auto_renew', TRUE); + $this->assign('autoRenewOption', 2); + } + } if (CRM_Core_Component::isEnabled('CiviMember') && empty($this->_ccid)) { if (isset($params['selectMembership']) && $params['selectMembership'] !== 'no_thanks' @@ -514,14 +523,12 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr $this->_membershipContactID, $params['selectMembership'] ); - if (!empty($params['auto_renew'])) { - $this->assign('auto_renew', TRUE); - } } else { $this->assign('membershipBlock', FALSE); } } + if (empty($this->_ccid)) { $this->buildCustom($this->_values['custom_pre_id'], 'customPre', TRUE); $this->buildCustom($this->_values['custom_post_id'], 'customPost', TRUE); diff --git a/CRM/Contribute/Form/Contribution/Main.php b/CRM/Contribute/Form/Contribution/Main.php index 501b950a4d..baf5578e3d 100644 --- a/CRM/Contribute/Form/Contribution/Main.php +++ b/CRM/Contribute/Form/Contribution/Main.php @@ -57,6 +57,23 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu */ private $existingMemberships; + /** + * @param array $fields + * + * @return string|null + * @throws \CRM_Core_Exception + */ + protected function getAutoRenewError(array $fields): ?string { + if (empty($fields['payment_processor_id'])) { + foreach ($this->getLineItems() as $lineItem) { + if ($lineItem['auto_renew'] === 2) { + return ts('You cannot have auto-renewal on if you are paying later.'); + } + } + } + return FALSE; + } + /** * Get the active UFGroups (profiles) on this form * Many forms load one or more UFGroups (profiles). @@ -694,12 +711,7 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu $this->assign('autoRenewOption', $autoRenewOption); if ((!$this->_values['is_pay_later'] || is_array($this->_paymentProcessors)) && ($allowAutoRenewMembership || $autoRenewOption)) { - if ($autoRenewOption == 2) { - $this->addElement('hidden', 'auto_renew', ts('Please renew my membership automatically.')); - } - else { - $this->addElement('checkbox', 'auto_renew', ts('Please renew my membership automatically.')); - } + $this->addElement('checkbox', 'auto_renew', ts('Please renew my membership automatically.')); } } @@ -799,11 +811,10 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu * true if no errors, else array of errors */ public static function formRule($fields, $files, $self) { - $errors = []; + $self->resetOrder($fields); + $errors = array_filter(['auto_renew' => $self->getAutoRenewError($fields)]); + // @todo - should just be $this->getOrder()->getTotalAmount() $amount = $self->computeAmount($fields, $self->_values); - if (!empty($fields['auto_renew']) && empty($fields['payment_processor_id'])) { - $errors['auto_renew'] = ts('You cannot have auto-renewal on if you are paying later.'); - } if ((!empty($fields['selectMembership']) && $fields['selectMembership'] != 'no_thanks' @@ -1149,9 +1160,8 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu $this->controller->resetPage('Confirm'); // Update order to the submitted values (in case the back button has been used // and the submitted values have changed. - $this->set('lineItem', NULL); - $this->order->setPriceSelectionFromUnfilteredInput($this->getSubmittedValues()); - $this->order->recalculateLineItems(); + // This aleady happens in validate so might be overkill. + $this->resetOrder($this->getSubmittedValues()); // get the submitted form values. $params = $this->controller->exportValues($this->_name); @@ -1944,4 +1954,25 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu } + /** + * @param array $fields + * @param bool $sanitized + * Has Quickform already sanitised the input. If not + * we will de-localize any money fields. + * + * @return void + * @throws \CRM_Core_Exception + */ + protected function resetOrder(array $fields, bool $sanitized = TRUE): void { + if (!$sanitized) { + // This happens in validate. + foreach ($fields as $fieldName => $value) { + $fields[$fieldName] = $this->getUnLocalizedSubmittedValue($fieldName, $value); + } + } + $this->set('lineItem', NULL); + $this->order->setPriceSelectionFromUnfilteredInput($fields); + $this->order->recalculateLineItems(); + } + } diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php index fcab41b3c2..efe2d064a6 100644 --- a/CRM/Core/Form.php +++ b/CRM/Core/Form.php @@ -3086,16 +3086,28 @@ class CRM_Core_Form extends HTML_QuickForm_Page { $this->exportedValues = $this->controller->exportValues($this->_name); } $value = $this->exportedValues[$fieldName] ?? NULL; + return $this->getUnLocalizedSubmittedValue($fieldName, $value); + } + + /** + * Sanitize by de-formatting any localised money. + * + * This should never be called from postProcess directly - + * getSubmittedValue() & getSubmittedValues() are the go. + * + * @internal - avoid using outside of core as this could change. + * + * @return mixed + */ + protected function getUnLocalizedSubmittedValue($fieldName, $value) { if (in_array($fieldName, $this->submittableMoneyFields, TRUE)) { return CRM_Utils_Rule::cleanMoney($value); } - else { - // Numeric fields are not in submittableMoneyFields (for now) - $fieldRules = $this->_rules[$fieldName] ?? []; - foreach ($fieldRules as $rule) { - if ('money' === $rule['type']) { - return CRM_Utils_Rule::cleanMoney($value); - } + // Numeric fields are not in submittableMoneyFields (for now) + $fieldRules = $this->_rules[$fieldName] ?? []; + foreach ($fieldRules as $rule) { + if ('money' === $rule['type']) { + return CRM_Utils_Rule::cleanMoney($value); } } return $value; diff --git a/CRM/Price/BAO/LineItem.php b/CRM/Price/BAO/LineItem.php index f54b31133a..8338cd637a 100644 --- a/CRM/Price/BAO/LineItem.php +++ b/CRM/Price/BAO/LineItem.php @@ -319,7 +319,7 @@ WHERE li.contribution_id = %1"; 'max_value' => $options[$oid]['max_value'] ?? NULL, 'membership_type_id' => $options[$oid]['membership_type_id'] ?? NULL, 'membership_num_terms' => $options[$oid]['membership_num_terms'] ?? NULL, - 'auto_renew' => $options[$oid]['auto_renew'] ?? NULL, + 'auto_renew' => !empty($options[$oid]['auto_renew']) ? (int) $options[$oid]['auto_renew'] : NULL, 'html_type' => $fields['html_type'], 'financial_type_id' => $options[$oid]['financial_type_id'] ?? NULL, 'tax_amount' => $options[$oid]['tax_amount'] ?? 0, @@ -327,7 +327,7 @@ WHERE li.contribution_id = %1"; ]; if ($values[$oid]['membership_type_id'] && empty($values[$oid]['auto_renew'])) { - $values[$oid]['auto_renew'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values[$oid]['membership_type_id'], 'auto_renew'); + $values[$oid]['auto_renew'] = (int) CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values[$oid]['membership_type_id'], 'auto_renew'); } } } -- 2.25.1