Skip to content
Snippets Groups Projects
Commit 4d97b2f7 authored by mattwire's avatar mattwire
Browse files

Support creating recurring payment (subscription)

parent 6f85fac9
Branches
Tags
No related merge requests found
......@@ -394,7 +394,6 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
// See if we already have a stripe customer
$customerParams = [
'contact_id' => $contactId,
'card_token' => $paymentIntentID,
'processor_id' => $this->_paymentProcessor['id'],
'email' => $email,
// Include this to allow redirect within session on payment failure
......@@ -409,19 +408,15 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
}
else {
// Customer was found in civicrm database, fetch from Stripe.
$deleteCustomer = FALSE;
try {
$stripeCustomer = \Stripe\Customer::retrieve($stripeCustomerId);
} catch (Exception $e) {
$err = self::parseStripeException('retrieve_customer', $e, FALSE);
if (($err['type'] == 'invalid_request_error') && ($err['code'] == 'resource_missing')) {
$deleteCustomer = TRUE;
}
$errorMessage = $this->handleErrorNotification($err, $params['stripe_error_url']);
throw new \Civi\Payment\Exception\PaymentProcessorException('Failed to create Stripe Charge: ' . $errorMessage);
throw new \Civi\Payment\Exception\PaymentProcessorException('Failed to retrieve Stripe Customer: ' . $errorMessage);
}
if ($deleteCustomer || $stripeCustomer->isDeleted()) {
if ($stripeCustomer->isDeleted()) {
// Customer doesn't exist, create a new one
CRM_Stripe_Customer::delete($customerParams);
try {
......@@ -439,17 +434,11 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
$params['description'] = E::ts('Backend Stripe contribution');
}
// Handle recurring payments in doRecurPayment().
if (CRM_Utils_Array::value('is_recur', $params) && $params['contributionRecurID']) {
// We set payment status as pending because the IPN will set it as completed / failed
$params['payment_status_id'] = $pendingStatusId;
return $this->doRecurPayment($params, $amount, $stripeCustomer);
}
// This is where we actually charge the customer
try {
$intent = \Stripe\PaymentIntent::retrieve($paymentIntentID);
$intent->description = $params['description'] . ' # Invoice ID: ' . CRM_Utils_Array::value('invoiceID', $params);
$intent->customer = $stripeCustomer->id;
switch ($intent->status) {
case 'requires_confirmation':
$intent->confirm();
......@@ -461,12 +450,22 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
catch (Exception $e) {
$this->handleError($e->getCode(), $e->getMessage(), $params['stripe_error_url']);
}
$stripeCharge = $intent->charges->data[0];
// This is where we save the customer card
$payment_method = \Stripe\PaymentMethod::retrieve($intent->payment_method);
$payment_method->attach(['customer' => $stripeCustomer->id]);
// Handle recurring payments in doRecurPayment().
if (CRM_Utils_Array::value('is_recur', $params) && $params['contributionRecurID']) {
// This is where we save the customer card
// @todo For a recurring payment we have to save the card. For a single payment we'd like to develop the
// save card functionality but should not save by default as the customer has not agreed.
$paymentMethod = \Stripe\PaymentMethod::retrieve($intent->payment_method);
$paymentMethod->attach(['customer' => $stripeCustomer->id]);
// We set payment status as pending because the IPN will set it as completed / failed
$params['payment_status_id'] = $pendingStatusId;
return $this->doRecurPayment($params, $amount, $stripeCustomer, $paymentMethod);
}
// Return fees & net amount for Civi reporting.
$stripeCharge = $intent->charges->data[0];
try {
$stripeBalanceTransaction = \Stripe\BalanceTransaction::retrieve($stripeCharge->balance_transaction);
}
......@@ -496,8 +495,9 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
* Assoc array of input parameters for this transaction.
* @param int $amount
* Transaction amount in USD cents.
* @param object $stripeCustomer
* @param \Stripe\Customer $stripeCustomer
* Stripe customer object generated by Stripe API.
* @param \Stripe\PaymentMethod $stripePaymentMethod
*
* @return array
* The result in a nice formatted array (or an error object).
......@@ -505,7 +505,7 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
* @throws \CiviCRM_API3_Exception
* @throws \CRM_Core_Exception
*/
public function doRecurPayment(&$params, $amount, $stripeCustomer) {
public function doRecurPayment($params, $amount, $stripeCustomer, $stripePaymentMethod) {
$requiredParams = ['contributionRecurID', 'frequency_unit'];
foreach ($requiredParams as $required) {
if (!isset($params[$required])) {
......@@ -524,6 +524,7 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
$subscriptionParams = [
'prorate' => FALSE,
'plan' => $planId,
'default_payment_method' => $stripePaymentMethod,
];
// Create the stripe subscription for the customer
$stripeSubscription = $stripeCustomer->subscriptions->create($subscriptionParams);
......
......@@ -131,7 +131,6 @@ class CRM_Stripe_Customer {
$stripeCustomerParams = [
'description' => $contactDisplayName . ' (CiviCRM)',
'card' => $params['card_token'],
'email' => CRM_Utils_Array::value('email', $params),
'metadata' => ['civicrm_contact_id' => $params['contact_id']],
];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment