Commit 72c1c91e authored by mattwire's avatar mattwire
Browse files

Refactor to support updating amount and re-confirming once we reach the thankyou page

parent ca3ae3e7
......@@ -523,11 +523,31 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
//$this->handleError('Amount differs', E::ts('Amount is different from the authorised amount (%1, %2)', [1 => $intent->amount, 2=> $this->getAmount($params)]), $params['stripe_error_url']);
}
$intent = \Stripe\PaymentIntent::update($params['paymentIntentID'], $intentParams);
if ($intent->status === 'requires_confirmation') {
$intent->confirm();
}
switch ($intent->status) {
case 'requires_confirmation':
$intent->confirm();
case 'requires_capture':
$intent->capture();
// Return fees & net amount for Civi reporting.
$stripeCharge = $intent->charges->data[0];
try {
$stripeBalanceTransaction = \Stripe\BalanceTransaction::retrieve($stripeCharge->balance_transaction);
}
catch (Exception $e) {
$err = self::parseStripeException('retrieve_balance_transaction', $e, FALSE);
$errorMessage = $this->handleErrorNotification($err, $params['stripe_error_url']);
throw new \Civi\Payment\Exception\PaymentProcessorException('Failed to retrieve Stripe Balance Transaction: ' . $errorMessage);
}
$newParams['fee_amount'] = $stripeBalanceTransaction->fee / 100;
$newParams['net_amount'] = $stripeBalanceTransaction->net / 100;
// Success!
// Set the desired contribution status which will be set later (do not set on the contribution here!)
$params['contribution_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
case 'requires_action':
\Civi::$statics['paymentIntentID'] = $params['paymentIntentID'];
if ((boolean) \Civi::settings()->get('stripe_oneoffreceipt')) {
// Send a receipt from Stripe - we have to set the receipt_email after the charge has been captured,
// as the customer receives an email as soon as receipt_email is updated and would receive two if we updated before capture.
......@@ -540,27 +560,11 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
$this->handleError($e->getCode(), $e->getMessage(), $params['stripe_error_url']);
}
// Return fees & net amount for Civi reporting.
$stripeCharge = $intent->charges->data[0];
try {
$stripeBalanceTransaction = \Stripe\BalanceTransaction::retrieve($stripeCharge->balance_transaction);
}
catch (Exception $e) {
$err = self::parseStripeException('retrieve_balance_transaction', $e, FALSE);
$errorMessage = $this->handleErrorNotification($err, $params['stripe_error_url']);
throw new \Civi\Payment\Exception\PaymentProcessorException('Failed to retrieve Stripe Balance Transaction: ' . $errorMessage);
}
// Success!
// Set the desired contribution status which will be set later (do not set on the contribution here!)
$params['contribution_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
// For contribution workflow we have a contributionId so we can set parameters directly.
// For events/membership workflow we have to return the parameters and they might get set...
// For a single charge there is no stripe invoice.
$this->setPaymentProcessorOrderID($stripeCharge->id);
$this->setPaymentProcessorTrxnID($stripeCharge->id);
$newParams['fee_amount'] = $stripeBalanceTransaction->fee / 100;
$newParams['net_amount'] = $stripeBalanceTransaction->net / 100;
return $this->endDoPayment($params, $newParams);
}
......
......@@ -42,6 +42,7 @@ class CRM_Stripe_AJAX {
$paymentMethodID = CRM_Utils_Request::retrieveValue('payment_method_id', 'String');
$paymentIntentID = CRM_Utils_Request::retrieveValue('payment_intent_id', 'String');
$amount = CRM_Utils_Request::retrieveValue('amount', 'Money');
$capture = CRM_Utils_Request::retrieveValue('capture', 'Boolean', FALSE);
$confirm = TRUE;
if (empty($amount)) {
$amount = 1;
......@@ -55,7 +56,15 @@ class CRM_Stripe_AJAX {
if ($paymentIntentID) {
// We already have a PaymentIntent, retrieve and attempt confirm.
$intent = \Stripe\PaymentIntent::retrieve($paymentIntentID);
$intent->confirm();
if ($intent->status === 'requires_confirmation') {
$intent->confirm();
}
if ($intent->status === 'requires_action') {
self::generatePaymentResponse($intent);
}
if ($capture) {
$intent->capture();
}
}
else {
// We don't yet have a PaymentIntent, create one using the
......@@ -103,6 +112,12 @@ class CRM_Stripe_AJAX {
'paymentIntent' => ['id' => $intent->id],
]);
}
elseif ($intent->status === 'succeeded') {
CRM_Utils_JSON::output([
'success' => true,
'paymentIntent' => ['id' => $intent->id],
]);
}
else {
// Invalid status
CRM_Utils_JSON::output(['error' => ['message' => 'Invalid PaymentIntent status']]);
......
/**
* JS Integration between CiviCRM & Stripe.
*/
CRM.$(function($) {
debugging("civicrm_stripe loaded, dom-ready function firing.");
checkAndLoad();
if (typeof stripe === 'undefined') {
stripe = Stripe(CRM.vars.stripe.publishableKey);
}
handleCardConfirm();
// On initial load...
var stripe;
var stripeLoading = false;
// Disable the browser "Leave Page Alert" which is triggered because we mess with the form submit function.
window.onbeforeunload = null;
function handleServerResponse(result) {
debugging('handleServerResponse');
if (result.error) {
// Show error from server on payment form
// displayError(result);
} else if (result.requires_action) {
// Use Stripe.js to handle required card action
handleAction(result);
} else {
// All good, nothing more to do
debugging('success - payment captured');
}
}
function handleAction(response) {
stripe.handleCardAction(response.payment_intent_client_secret)
.then(function(result) {
if (result.error) {
// Show error in payment form
handleCardConfirm();
} else {
// The card action has been handled
debugging('card action success');
handleCardConfirm();
}
});
}
function handleCardConfirm() {
debugging('handle card confirm');
// Send paymentMethod.id to server
var url = CRM.url('civicrm/stripe/confirm-payment');
$.post(url, {
payment_intent_id: CRM.vars.stripe.paymentIntentID,
capture: true,
id: CRM.vars.stripe.id,
}).then(function (result) {
// Handle server response (see Step 3)
handleServerResponse(result);
});
}
function checkAndLoad() {
if (typeof CRM.vars.stripe === 'undefined') {
debugging('CRM.vars.stripe not defined! Not a Stripe processor?');
return;
}
if (typeof Stripe === 'undefined') {
if (stripeLoading) {
return;
}
stripeLoading = true;
debugging('Stripe.js is not loaded!');
$.getScript("https://js.stripe.com/v3", function () {
debugging("Script loaded and executed.");
stripeLoading = false;
});
}
}
function debugging(errorCode) {
// Uncomment the following to debug unexpected returns.
if ((typeof(CRM.vars.stripe) === 'undefined') || (Boolean(CRM.vars.stripe.jsDebug) === true)) {
console.log(new Date().toISOString() + ' civicrm_stripe.js: ' + errorCode);
}
}
});
......@@ -126,6 +126,23 @@ function stripe_civicrm_buildForm($formName, &$form) {
\Civi::resources()->addScriptUrl('https://js.stripe.com/v3');
\Civi::$statics[E::LONG_NAME]['stripeJSLoaded'] = TRUE;
}
switch ($formName) {
case 'CRM_Contribution_Form_ThankYou':
case 'CRM_Event_Form_Registration_ThankYou':
\Civi::resources()->addScriptFile(E::LONG_NAME, 'js/civicrmStripeConfirm.js');
// @todo: Not working yet because the paymentIntentID doesn't get passed - let's save/retrieve from db (use contribution and/or session key)
$jsVars = [
'id' => $form->_paymentProcessor['id'],
'paymentIntentID' => \Civi::$statics['paymentIntentID'],
'publishableKey' => CRM_Core_Payment_Stripe::getPublicKeyById($form->_paymentProcessor['id']),
'jsDebug' => (boolean) \Civi::settings()->get('stripe_jsdebug'),
];
\Civi::resources()->addVars(E::SHORT_NAME, $jsVars);
break;
}
}
/**
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment