Skip to content
Snippets Groups Projects
Commit 9943d703 authored by mattwire's avatar mattwire Committed by mattwire
Browse files

paymentRequest button now submits and completes payment

parent 92ccd855
No related branches found
No related tags found
1 merge request!1526.6 to master
...@@ -14,6 +14,11 @@ ...@@ -14,6 +14,11 @@
var stripeLoading = false; var stripeLoading = false;
var paymentProcessorID = null; var paymentProcessorID = null;
var paymentData = {
clientSecret: null,
paymentRequest: null
};
// Disable the browser "Leave Page Alert" which is triggered because we mess with the form submit function. // Disable the browser "Leave Page Alert" which is triggered because we mess with the form submit function.
window.onbeforeunload = null; window.onbeforeunload = null;
...@@ -232,6 +237,45 @@ ...@@ -232,6 +237,45 @@
}); });
} }
function handleSubmitPaymentRequestButton(submitEvent) {
debugging('handle submit paymentRequestButton');
// Send paymentMethod.id to server
debugging('Waiting for pre-auth');
swalFire({
title: ts('Please wait'),
text: ts(' preparing your payment...'),
allowOutsideClick: false,
onBeforeOpen: function() {
Swal.showLoading();
}
}, '', false);
CRM.api3('StripePaymentintent', 'Process', {
amount: CRM.payment.getTotalAmount().toFixed(2),
currency: CRM.payment.getCurrency(CRM.vars.stripe.currency),
id: CRM.vars.stripe.id,
description: document.title,
csrfToken: CRM.vars.stripe.csrfToken
//metadata: {integration_check: accept_a_payment}
})
.done(function(result) {
// Handle server response (see Step 3)
swalClose();
// Trigger the paymentRequest dialog
paymentData.clientSecret = result.values.payment_intent_client_secret;
paymentData.paymentRequest.show();
// From here the on 'paymentmethod' of the paymentRequest handles completion/failure
})
.fail(function(result) {
var error = 'Unknown error';
if (result.hasOwnProperty('statusText')) {
error = result.statusText;
}
swalClose();
displayError(error, true);
});
}
function handleServerResponse(result) { function handleServerResponse(result) {
debugging('handleServerResponse'); debugging('handleServerResponse');
if (result.error) { if (result.error) {
...@@ -246,16 +290,17 @@ ...@@ -246,16 +290,17 @@
} }
} }
function handleAction(response) { function handleAction(result) {
stripe.handleCardAction(response.payment_intent_client_secret) paymentData.clientSecret = result.payment_intent_client_secret;
.then(function(result) { stripe.handleCardAction(paymentData.clientSecret)
if (result.error) { .then(function(cardActionResult) {
if (cardActionResult.error) {
// Show error in payment form // Show error in payment form
displayError(result.error.message, true); displayError(cardActionResult.error.message, true);
} else { } else {
// The card action has been handled // The card action has been handled
// The PaymentIntent can be confirmed again on the server // The PaymentIntent can be confirmed again on the server
successHandler('paymentIntentID', result.paymentIntent); successHandler('paymentIntentID', cardActionResult.paymentIntent);
} }
}); });
} }
...@@ -318,6 +363,10 @@ ...@@ -318,6 +363,10 @@
function loadStripeBillingBlock() { function loadStripeBillingBlock() {
debugging('loadStripeBillingBlock'); debugging('loadStripeBillingBlock');
// When switching payment processors we need to make sure these are empty
paymentData.clientSecret = null;
paymentData.paymentRequest = null;
var oldPaymentProcessorID = paymentProcessorID; var oldPaymentProcessorID = paymentProcessorID;
paymentProcessorID = getPaymentProcessorSelectorValue(); paymentProcessorID = getPaymentProcessorSelectorValue();
debugging('payment processor old: ' + oldPaymentProcessorID + ' new: ' + paymentProcessorID + ' id: ' + CRM.vars.stripe.id); debugging('payment processor old: ' + oldPaymentProcessorID + ' new: ' + paymentProcessorID + ' id: ' + CRM.vars.stripe.id);
...@@ -361,7 +410,7 @@ ...@@ -361,7 +410,7 @@
submitButtons[i].addEventListener('click', submitButtonClick); submitButtons[i].addEventListener('click', submitButtonClick);
} }
function submitButtonClick(event) { function submitButtonClick(clickEvent) {
// Take over the click function of the form. // Take over the click function of the form.
if (typeof CRM.vars.stripe === 'undefined') { if (typeof CRM.vars.stripe === 'undefined') {
// Submit the form // Submit the form
...@@ -372,7 +421,7 @@ ...@@ -372,7 +421,7 @@
// Run through our own submit, that executes Stripe submission if // Run through our own submit, that executes Stripe submission if
// appropriate for this submit. // appropriate for this submit.
return submit(event); return submit(clickEvent);
} }
// Remove the onclick attribute added by CiviCRM. // Remove the onclick attribute added by CiviCRM.
...@@ -390,10 +439,10 @@ ...@@ -390,10 +439,10 @@
addDrupalWebformActionElement(this.value); addDrupalWebformActionElement(this.value);
}); });
// If enter pressed, use our submit function // If enter pressed, use our submit function
form.addEventListener('keydown', function (event) { form.addEventListener('keydown', function (keydownEvent) {
if (event.code === 'Enter') { if (keydownEvent.code === 'Enter') {
addDrupalWebformActionElement(this.value); addDrupalWebformActionElement(this.value);
submit(event); submit(keydownEvent);
} }
}); });
...@@ -540,8 +589,17 @@ ...@@ -540,8 +589,17 @@
submitButtons[i].setAttribute('disabled', true); submitButtons[i].setAttribute('disabled', true);
} }
// When we click the stripe element we already have the elementType.
// But clicking an alternative submit button we have to work it out.
var elementType = 'card';
if (submitEvent.hasOwnProperty(elementType)) {
elementType = submitEvent.elementType;
}
else if (paymentData.paymentRequest !== null) {
elementType = 'paymentRequestButton';
}
// Create a token when the form is submitted. // Create a token when the form is submitted.
switch(submitEvent.elementType) { switch(elementType) {
case 'card': case 'card':
handleSubmitCard(submitEvent); handleSubmitCard(submitEvent);
break; break;
...@@ -628,81 +686,91 @@ ...@@ -628,81 +686,91 @@
return false; return false;
}) })
.then(function(result) { .then(function(result) {
elements.paymentRequestButton = stripeElements.create('paymentRequestButton', { paymentData.paymentRequest = paymentRequest;
paymentRequest: paymentRequest, elements.paymentRequestButton = stripeElements.create('paymentRequestButton', {
style: { paymentRequest: paymentRequest,
paymentRequestButton: { style: {
// One of 'default', 'book', 'buy', or 'donate' paymentRequestButton: {
type: 'default', // One of 'default', 'book', 'buy', or 'donate'
// One of 'dark', 'light', or 'light-outline' type: 'default',
theme: 'dark', // One of 'dark', 'light', or 'light-outline'
// Defaults to '40px'. The width is always '100%'. theme: 'dark',
height: '64px' // Defaults to '40px'. The width is always '100%'.
} height: '64px'
} }
});
elements.paymentRequestButton.on('click', function(event) {
debugging('PaymentRequest clicked');
paymentRequest.update({
total: {
label: document.title,
amount: CRM.payment.getTotalAmount() * 100
} }
}); });
debugging('clearing submitdontprocess');
form.dataset.submitdontprocess = 'false';
// Run through our own submit, that executes Stripe submission if elements.paymentRequestButton.on('click', function(clickEvent) {
// appropriate for this submit. debugging('PaymentRequest clicked');
//parent.submit(event); paymentRequest.update({
return submit(event); total: {
label: document.title,
amount: CRM.payment.getTotalAmount() * 100
}
});
debugging('clearing submitdontprocess');
form.dataset.submitdontprocess = 'false';
form.dataset.submitted = 'false';
}); // Run through our own submit, that executes Stripe submission if
// appropriate for this submit.
submit(clickEvent);
});
paymentRequest.on('paymentmethod', function(ev) { paymentRequest.on('paymentmethod', function(paymentRequestEvent) {
// Confirm the PaymentIntent without handling potential next actions (yet). try {
stripe.confirmCardPayment( // Confirm the PaymentIntent without handling potential next actions (yet).
clientSecret, stripe.confirmCardPayment(
{payment_method: ev.paymentMethod.id}, paymentData.clientSecret,
{handleActions: false} {payment_method: paymentRequestEvent.paymentMethod.id},
).then(function(confirmResult) { {handleActions: false}
if (confirmResult.error) { ).then(function(confirmResult) {
// Report to the browser that the payment failed, prompting it to if (confirmResult.error) {
// re-show the payment interface, or show an error message and close // Report to the browser that the payment failed, prompting it to
// the payment interface. // re-show the payment interface, or show an error message and close
ev.complete('fail'); // the payment interface.
} else { paymentRequestEvent.complete('fail');
// Report to the browser that the confirmation was successful, prompting } else {
// it to close the browser payment method collection interface. // Report to the browser that the confirmation was successful, prompting
ev.complete('success'); // it to close the browser payment method collection interface.
// Check if the PaymentIntent requires any actions and if so let Stripe.js paymentRequestEvent.complete('success');
// handle the flow. If using an API version older than "2019-02-11" instead // Check if the PaymentIntent requires any actions and if so let Stripe.js
// instead check for: `paymentIntent.status === "requires_source_action"`. // handle the flow.
if (confirmResult.paymentIntent.status === "requires_action") { if (confirmResult.paymentIntent.status === "requires_action") {
// Let Stripe.js handle the rest of the payment flow. // Let Stripe.js handle the rest of the payment flow.
stripe.confirmCardPayment(clientSecret).then(function(result) { stripe.confirmCardPayment(paymentData.clientSecret).then(function(result) {
if (result.error) { if (result.error) {
// The payment failed -- ask your customer for a new payment method. // The payment failed -- ask your customer for a new payment method.
debugging('confirmCardPayment failed');
displayError('The payment failed - please try a different payment method.', true);
} else {
// The payment has succeeded.
successHandler('paymentIntentID', result.paymentIntent);
}
});
} else { } else {
// The payment has succeeded. // The payment has succeeded.
successHandler('paymentIntentID', confirmResult.paymentIntent);
} }
}); }
} else { });
// The payment has succeeded. } catch(err) {
if (err.name === 'IntegrationError') {
debugging(err.message);
} }
paymentRequestEvent.complete('fail');
} }
}); });
});
if (result) { if (result) {
elements.paymentRequestButton.mount('#paymentrequest-element'); elements.paymentRequestButton.mount('#paymentrequest-element');
document.getElementById('paymentrequest-element').style.display = 'block'; document.getElementById('paymentrequest-element').style.display = 'block';
} else { } else {
document.getElementById('paymentrequest-element').style.display = 'none'; document.getElementById('paymentrequest-element').style.display = 'none';
} }
return true; });
});
} }
/** /**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment