Skip to content
This repository has been archived by the owner on Jun 25, 2021. It is now read-only.

Commit

Permalink
Support changing, cancelling subscriptions - using processor_id for s…
Browse files Browse the repository at this point in the history
…ubscription_id
  • Loading branch information
Rich Lott / Artful Robot committed Nov 26, 2019
1 parent 351a177 commit b1d90d7
Showing 1 changed file with 45 additions and 39 deletions.
84 changes: 45 additions & 39 deletions CRM/Core/Payment/GoCardless.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Payment Processor for GoCardless.
*/
use CRM_GoCardless_ExtensionUtil as E;
use \Civi\Payment\Exception\PaymentProcessorException;
use Civi\Payment\Exception\PaymentProcessorException;

/**
*
Expand All @@ -29,6 +29,7 @@ class CRM_Core_Payment_GoCardless extends CRM_Core_Payment {
* @var array
*/
protected $editableScheduleFields = [];

/**
* Constructor
*
Expand Down Expand Up @@ -89,56 +90,58 @@ public function checkConfig() {
public function buildForm(&$form) {
//$form->add('select', 'preferred_collection_day', E::ts('Preferred Collection Day'), $collectionDaysArray, FALSE);
}

/**
* Attempt to cancel the subscription at GoCardless.
*
* @see supportsCancelRecurring()
*
* @param string $message
* @param array $params. We can't use this though as it only has
* 'subscriptionId' (which actually relates to
* civicrm_contribution_recur.processor_id)
* @param array $params
* which refers to 'subscriptionId'
*
* @return bool
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public function cancelSubscription(&$message = '', $params = []) {
// Get the GoCardless subscription ID, stored in trxn_id
$contrib_recur = civicrm_api3('ContributionRecur', 'getsingle', ['id' => $this->getContributionRecurID()]);
$subscription_id = $contrib_recur['trxn_id'] ?? NULL;
if (!$subscription_id) {
throw new PaymentProcessorException("Missing GoCardless subscription ID in ContributionRecur trxn_id field. Cannot process changing subscription amount.");
if (empty($params['subscriptionId'])) {
throw new PaymentProcessorException("cancelSubscription requires a subscriptionId");
}
// Get the GoCardless subscription ID, stored in processor_id
$contrib_recur = civicrm_api3('ContributionRecur', 'getsingle', ['processor_id' => $params['subscriptionId']]);
$subscription_id = $contrib_recur['processor_id'];

$log_message = __FUNCTION__ . ": "
. json_encode(['subscription_id' => $subscription_id, 'contribution_recur_id' => $params['id']])
. ' ';
$log_message = __FUNCTION__ . ": "
. json_encode(['subscription_id' => $subscription_id, 'contribution_recur_id' => $params['id']])
. ' ';
try {
$gc_api = $this->getGoCardlessApi();
$gc_api->subscriptions()->cancel($subscription_id);
CRM_Core_Error::debug_log_message("$log_message SUCCESS", FALSE, 'GoCardless', PEAR_LOG_INFO);
}
catch (\GoCardlessPro\Core\Exception\ApiException $e) {
// Api request failed / record couldn't be created.
catch (\GoCardlessPro\Core\Exception\ApiException $e) {
// Api request failed / record couldn't be created.
$this->logGoCardlessException("$log_message FAILED", $e);
// repackage as PaymentProcessorException
throw new PaymentProcessorException($e->getMessage());

} catch (\GoCardlessPro\Core\Exception\MalformedResponseException $e) {
// Unexpected non-JSON response
}
catch (\GoCardlessPro\Core\Exception\MalformedResponseException $e) {
// Unexpected non-JSON response
$this->logGoCardlessException("$log_message FAILED", $e);
throw new PaymentProcessorException('Unexpected response type from GoCardless');

} catch (\GoCardlessPro\Core\Exception\ApiConnectionException $e) {
// Network error
}
catch (\GoCardlessPro\Core\Exception\ApiConnectionException $e) {
// Network error
$this->logGoCardlessException("$log_message FAILED", $e);
throw new PaymentProcessorException('Network error, please try later.');
}


$message = "Successfully cancelled the subscription at GoCardless.";
return TRUE;
}

/**
* Attempt to change the subscription at GoCardless.
*
Expand All @@ -149,7 +152,7 @@ public function cancelSubscription(&$message = '', $params = []) {
* - We can only change the amount (not frequency etc)
*
* @param string $message
* @param array $params. The following are required in this implementation:
* @param array $params
*
* - id: ContributionRecur ID
* - amount: new amount
Expand All @@ -158,8 +161,7 @@ public function cancelSubscription(&$message = '', $params = []) {
* CRM_Contribute_Form_UpdateSubscription but are not required/used.
*
* - subscriptionId: This is the value of ContributionRecur.processor_id
* however currrently (v1.8, Oct 2019) we don't use this; the GoCardless
* subscription ID is stored in the ContributionRecur.trxn_id field
* which (as of v1.9) relates to the GoCardless subscription ID.
* - is_notify: 0|1 whether to notify the user (not implemented here)
* - installments: new No. installments (can be blank)
* - (campaign_id): only present if we support that
Expand All @@ -172,11 +174,11 @@ public function cancelSubscription(&$message = '', $params = []) {
* @throws \Civi\Payment\Exception\PaymentProcessorException
*/
public function changeSubscriptionAmount(&$message = '', $params = []) {
// Get the GoCardless subscription ID, stored in trxn_id
// Get the GoCardless subscription ID, stored in processor_id
$contrib_recur = civicrm_api3('ContributionRecur', 'getsingle', ['id' => $params['id']]);
$subscription_id = $contrib_recur['trxn_id'] ?? NULL;
$subscription_id = $contrib_recur['processor_id'] ?? NULL;
if (!$subscription_id) {
throw new PaymentProcessorException("Missing GoCardless subscription ID in ContributionRecur trxn_id field. Cannot process changing subscription amount.");
throw new PaymentProcessorException("Missing GoCardless subscription ID in ContributionRecur processor_id field. Cannot process changing subscription amount.");
}

if (empty($params['amount']) || ((float) $params['amount']) < 0.01) {
Expand All @@ -192,31 +194,34 @@ public function changeSubscriptionAmount(&$message = '', $params = []) {

$subscription_updates = [
'params' => [
'amount' => (int) (100 * $params['amount']), // Convert to pennies.
]
// Convert to pennies.
'amount' => (int) (100 * $params['amount']),
],
];

$log_message = __FUNCTION__ . ": "
. json_encode(['subscription_id' => $subscription_id, 'contribution_recur_id' => $params['id']])
. ' ';
$log_message = __FUNCTION__ . ": "
. json_encode(['subscription_id' => $subscription_id, 'contribution_recur_id' => $params['id']])
. ' ';
try {
$gc_api = $this->getGoCardlessApi();
$gc_api->subscriptions()->update($subscription_id, $subscription_updates);
CRM_Core_Error::debug_log_message("$log_message SUCCESS", FALSE, 'GoCardless', PEAR_LOG_INFO);
}
catch (\GoCardlessPro\Core\Exception\ApiException $e) {
// Api request failed / record couldn't be created.
catch (\GoCardlessPro\Core\Exception\ApiException $e) {
// Api request failed / record couldn't be created.
$this->logGoCardlessException("$log_message FAILED", $e);
// repackage as PaymentProcessorException
throw new PaymentProcessorException($e->getMessage());

} catch (\GoCardlessPro\Core\Exception\MalformedResponseException $e) {
// Unexpected non-JSON response
}
catch (\GoCardlessPro\Core\Exception\MalformedResponseException $e) {
// Unexpected non-JSON response
$this->logGoCardlessException("$log_message FAILED", $e);
throw new PaymentProcessorException('Unexpected response type from GoCardless');

} catch (\GoCardlessPro\Core\Exception\ApiConnectionException $e) {
// Network error
}
catch (\GoCardlessPro\Core\Exception\ApiConnectionException $e) {
// Network error
$this->logGoCardlessException("$log_message FAILED", $e);
throw new PaymentProcessorException('Network error, please try later.');
}
Expand Down Expand Up @@ -479,8 +484,8 @@ public function setGoCardlessApi($mocked_api) {
* Shared code to handle extracting info from a gocardless exception.
* @see https://github.com/gocardless/gocardless-pro-php/
*/
protected function logGoCardlessException($prefix, $e) {
CRM_Core_Error::debug_log_message(
protected function logGoCardlessException($prefix, $e) {
CRM_Core_Error::debug_log_message(
"$prefix" . json_encode([
'message' => $e->getMessage(),
'type' => $e->getType(),
Expand All @@ -489,7 +494,8 @@ protected function logGoCardlessException($prefix, $e) {
'documentationUrl' => $e->getDocumentationUrl(),
], JSON_PRETTY_PRINT),
FALSE, 'GoCardless', PEAR_LOG_INFO);
}
}

/**
* Does this processor support cancelling recurring contributions through code.
*
Expand Down

0 comments on commit b1d90d7

Please sign in to comment.