From 5077b04cabe3ad1ce36ce350b4c2cc88b79f21d3 Mon Sep 17 00:00:00 2001 From: eileen Date: Thu, 23 Apr 2020 11:08:05 +1200 Subject: [PATCH] Nuance cancel options for processors. This PR addresses an issue where we have insufficient nuance on processor capabilities for cancel. There are 2 behaviours that we are trying to support with one capability 1) can this processor cope with us cancelling a recurring donation within CiviCRM 2) should we present the option of whether to or not to a user. This option is appropriate when the processor manages the schedule (e.g Paypal) as the user may just be updating Civi to match reality. However, for token driven processors it generally doesnt' apply. This PR adds a new overridable capability - 'supportsOptionalCancelRecurring' which is the same as supportsCancelRecurring by default. For the manual processor it is FALSE. Call cancelRecurring for all cancels. In almost all cases this will be no change as processors would have to implement the new-ish doCancelRecurring themselves to have any change --- CRM/Contribute/Form/CancelSubscription.php | 25 +++++++-------- CRM/Core/Payment.php | 21 ++++++++++-- CRM/Core/Payment/Manual.php | 13 ++++++++ Civi/Payment/PropertyBag.php | 32 +++++++++++++++++++ .../Contribute/Form/CancelSubscription.tpl | 2 +- 5 files changed, 77 insertions(+), 16 deletions(-) diff --git a/CRM/Contribute/Form/CancelSubscription.php b/CRM/Contribute/Form/CancelSubscription.php index 831b5e9b55..367336d14d 100644 --- a/CRM/Contribute/Form/CancelSubscription.php +++ b/CRM/Contribute/Form/CancelSubscription.php @@ -133,8 +133,7 @@ class CRM_Contribute_Form_CancelSubscription extends CRM_Contribute_Form_Contrib public function buildQuickForm() { $this->buildQuickEntityForm(); // Determine if we can cancel recurring contribution via API with this processor - $cancelSupported = $this->_paymentProcessorObj->supports('CancelRecurring'); - if ($cancelSupported) { + if ($this->_paymentProcessorObj->supports('CancelRecurringNotifyOptional')) { $searchRange = []; $searchRange[] = $this->createElement('radio', NULL, NULL, ts('Yes'), '1'); $searchRange[] = $this->createElement('radio', NULL, NULL, ts('No'), '0'); @@ -149,7 +148,6 @@ class CRM_Contribute_Form_CancelSubscription extends CRM_Contribute_Form_Contrib else { $this->assign('cancelRecurNotSupportedText', $this->_paymentProcessorObj->getText('cancelRecurNotSupportedText', [])); } - $this->assign('cancelSupported', $cancelSupported); if (!empty($this->_donorEmail)) { $this->add('checkbox', 'is_notify', ts('Notify Contributor?') . " ({$this->_donorEmail})"); @@ -195,6 +193,8 @@ class CRM_Contribute_Form_CancelSubscription extends CRM_Contribute_Form_Contrib /** * Process the form submission. + * + * @throws \CRM_Core_Exception */ public function postProcess() { $message = NULL; @@ -212,16 +212,15 @@ class CRM_Contribute_Form_CancelSubscription extends CRM_Contribute_Form_Contrib } } - if (CRM_Utils_Array::value('send_cancel_request', $params) == 1) { - try { - $propertyBag = new PropertyBag(); - $propertyBag->setContributionRecurID($this->getSubscriptionDetails()->recur_id); - $propertyBag->setRecurProcessorID($this->getSubscriptionDetails()->subscription_id); - $message = $this->_paymentProcessorObj->doCancelRecurring($propertyBag)['message']; - } - catch (\Civi\Payment\Exception\PaymentProcessorException $e) { - CRM_Core_Error::statusBounce($e->getMessage()); - } + try { + $propertyBag = new PropertyBag(); + $propertyBag->setIsNotifyProcessorOnCancelRecur(!empty($params['send_cancel_request'])); + $propertyBag->setContributionRecurID($this->getSubscriptionDetails()->recur_id); + $propertyBag->setRecurProcessorID($this->getSubscriptionDetails()->subscription_id); + $message = $this->_paymentProcessorObj->doCancelRecurring($propertyBag)['message']; + } + catch (\Civi\Payment\Exception\PaymentProcessorException $e) { + CRM_Core_Error::statusBounce($e->getMessage()); } if ($cancelSubscription) { diff --git a/CRM/Core/Payment.php b/CRM/Core/Payment.php index 288359d4e5..5b6a477cb1 100644 --- a/CRM/Core/Payment.php +++ b/CRM/Core/Payment.php @@ -399,6 +399,19 @@ abstract class CRM_Core_Payment { return method_exists(CRM_Utils_System::getClassName($this), 'cancelSubscription'); } + /** + * Does the processor support the user having a choice as to whether to cancel the recurring with the processor? + * + * If this returns TRUE then there will be an option to send a cancellation request in the cancellation form. + * + * This would normally be false for processors where CiviCRM maintains the schedule. + * + * @return bool + */ + protected function supportsCancelRecurringNotifyOptional() { + return $this->supportsCancelRecurring(); + } + /** * Does this processor support pre-approval. * @@ -615,7 +628,10 @@ abstract class CRM_Core_Payment { } case 'cancelRecurNotSupportedText': - return ts('Automatic cancellation is not supported for this payment processor. You or the contributor will need to manually cancel this recurring contribution using the payment processor website.'); + if (!$this->supportsCancelRecurring()) { + return ts('Automatic cancellation is not supported for this payment processor. You or the contributor will need to manually cancel this recurring contribution using the payment processor website.'); + } + return ''; } CRM_Core_Error::deprecatedFunctionWarning('Calls to getText must use a supported method'); @@ -1382,7 +1398,8 @@ abstract class CRM_Core_Payment { * @throws \Civi\Payment\Exception\PaymentProcessorException */ public function doCancelRecurring(PropertyBag $propertyBag) { - if (method_exists($this, 'cancelSubscription')) { + if (method_exists($this, 'cancelSubscription') + && $propertyBag->getIsNotifyProcessorOnCancelRecur()) { $message = NULL; if ($this->cancelSubscription($message, $propertyBag)) { return ['message' => $message]; diff --git a/CRM/Core/Payment/Manual.php b/CRM/Core/Payment/Manual.php index 3027564199..0a311b48da 100644 --- a/CRM/Core/Payment/Manual.php +++ b/CRM/Core/Payment/Manual.php @@ -196,6 +196,19 @@ class CRM_Core_Payment_Manual extends CRM_Core_Payment { return TRUE; } + /** + * Does the processor support the user having a choice as to whether to cancel the recurring with the processor? + * + * If this returns TRUE then there will be an option to send a cancellation request in the cancellation form. + * + * This would normally be false for processors where CiviCRM maintains the schedule. + * + * @return bool + */ + protected function supportsCancelRecurringNotifyOptional() { + return FALSE; + } + /** * Are back office payments supported. * diff --git a/Civi/Payment/PropertyBag.php b/Civi/Payment/PropertyBag.php index 4423fce5ec..3fc564183f 100644 --- a/Civi/Payment/PropertyBag.php +++ b/Civi/Payment/PropertyBag.php @@ -72,6 +72,7 @@ class PropertyBag implements \ArrayAccess { 'transactionID' => TRUE, 'transaction_id' => 'transactionID', 'trxnResultCode' => TRUE, + 'isNotifyProcessorOnCancelRecur' => TRUE, ]; /** @@ -480,6 +481,8 @@ class PropertyBag implements \ArrayAccess { * * @param string $input * @param string $label e.g. 'default' + * + * @return \Civi\Payment\PropertyBag */ public function setBillingCity($input, $label = 'default') { return $this->set('billingCity', $label, (string) $input); @@ -794,6 +797,35 @@ class PropertyBag implements \ArrayAccess { return $this->set('isRecur', $label, (bool) $isRecur); } + /** + * Set whether the user has selected to notify the processor of a cancellation request. + * + * When cancelling the user may be presented with an option to notify the processor. The payment + * processor can take their response, if present, into account. + * + * @param bool $value + * @param string $label e.g. 'default' + * + * @return \Civi\Payment\PropertyBag + */ + public function setIsNotifyProcessorOnCancelRecur($value, $label = 'default') { + return $this->set('isNotifyProcessorOnCancelRecur', $label, (bool) $value); + } + + /** + * Get whether the user has selected to notify the processor of a cancellation request. + * + * When cancelling the user may be presented with an option to notify the processor. The payment + * processor can take their response, if present, into account. + * + * @param string $label e.g. 'default' + * + * @return \Civi\Payment\PropertyBag + */ + public function getIsNotifyProcessorOnCancelRecur($label = 'default') { + return $this->get('isNotifyProcessorOnCancelRecur', $label); + } + /** * Last name * diff --git a/templates/CRM/Contribute/Form/CancelSubscription.tpl b/templates/CRM/Contribute/Form/CancelSubscription.tpl index 74e5e2f186..c193513b62 100644 --- a/templates/CRM/Contribute/Form/CancelSubscription.tpl +++ b/templates/CRM/Contribute/Form/CancelSubscription.tpl @@ -12,7 +12,7 @@
  {$cancelRecurDetailText} - {if !$cancelSupported} + {if $cancelRecurNotSupportedText}
{$cancelRecurNotSupportedText}
{/if}
-- 2.25.1