7.x-3.1 release.

This commit is contained in:
Matt
2019-10-03 22:00:38 -05:00
parent aea105c1ab
commit db9d45834a
11 changed files with 1125 additions and 373 deletions

View File

@ -8,164 +8,186 @@
Drupal.behaviors.uc_stripe = {
attach: function (context) {
// Once function prevents stripe from reloading. Any dom changes to stripe area will destroy element
// as a Stripe security feature
$('#uc-cart-checkout-form', context).once('uc_stripe', function(){
var stripe_card_element = '#stripe-card-element';
if (Drupal.settings && Drupal.settings.uc_stripe ) {
var apikey = Drupal.settings.uc_stripe.apikey;
var stripe = Stripe(apikey);
var elements = stripe.elements();
}
// Map stripe names to (partial) Ubercart field names; Ubercart names add "billing_" or "shipping_" on the front.
const address_field_mapping = {
"address_line1": "street1",
"address_line2": "street2",
"address_city": "city",
"address_state": "zone",
"address_zip": "postal_code",
"address_country": "country"
};
var submitButton = $('.uc-cart-checkout-form #edit-continue');
const address_field_mapping = {
"address_line1": "street1",
"address_line2": "street2",
"address_city": "city",
"address_state": "zone",
"address_zip": "postal_code",
"address_country": "country"
};
var submitButton = $('.uc-cart-checkout-form #edit-continue');
var cc_container = $('.payment-details-credit');
var cc_num = cc_container.find(':input[id*="edit-panes-payment-details-cc-numbe"]');
var cc_cvv = cc_container.find(':input[id*="edit-panes-payment-details-cc-cv"]');
// Load the js reference to these fields so that on the review page
// we can input the last 4 and expiration date which is returned to us by stripe paymentMethod call
var cc_container = $('.payment-details-credit');
var cc_num = cc_container.find(':input[id*="edit-panes-payment-details-cc-numbe"]');
var cc_cvv = cc_container.find(':input[id*="edit-panes-payment-details-cc-cv"]');
var cc_exp_month = cc_container.find('#edit-panes-payment-details-cc-exp-month');
var cc_exp_year = cc_container.find('#edit-panes-payment-details-cc-exp-year');
// Make sure that when the page is being loaded the paymentMethod value is reset
// Browser or other caching might do otherwise.
$("[name='panes[payment-stripe][details][stripe_payment_method]']").val('default');
// Make sure that when the page is being loaded the token value is reset
// Browser or other caching might do otherwise.
$("[name='panes[payment][details][stripe_token]']").val('default');
// JS must enable the button; otherwise form might disclose cc info. It starts disabled
submitButton.attr('disabled', false);
$('span#stripe-nojs-warning').parent().hide();
// JS must enable the button; otherwise form might disclose cc info. It starts disabled
submitButton.attr('disabled', false);
// When this behavior fires, we can clean the form so it will behave properly,
// Remove 'name' from sensitive form elements so there's no way they can be submitted.
cc_num.removeAttr('name').removeAttr('disabled');
$('div.form-item-panes-payment-details-cc-number').removeClass('form-disabled');
cc_cvv.removeAttr('name').removeAttr('disabled');
var cc_val_val = cc_num.val();
if (cc_val_val && cc_val_val.indexOf('Last 4')) {
cc_num.val('');
}
submitButton.click(function (e) {
// We must find the various fields again, because they may have been swapped
// in by ajax action of the form.
cc_container = $('.payment-details-credit');
cc_num = cc_container.find(':input[id*="edit-panes-payment-details-cc-numbe"]');
cc_cvv = cc_container.find(':input[id*="edit-panes-payment-details-cc-cv"]');
// If not credit card processing or no token field, just let the submit go on
// Also continue if we've received the tokenValue
var tokenField = $("[name='panes[payment][details][stripe_token]']");
if (!$("div.payment-details-credit").length || !tokenField.length || tokenField.val().indexOf('tok_') == 0) {
return true;
// When this behavior fires, we can clean the form so it will behave properly,
// Remove 'name' from sensitive form elements so there's no way they can be submitted.
cc_num.removeAttr('name').removeAttr('disabled');
$('div.form-item-panes-payment-details-cc-number').removeClass('form-disabled');
cc_cvv.removeAttr('name').removeAttr('disabled');
var cc_val_val = cc_num.val();
if (cc_val_val && cc_val_val.indexOf('Last 4')) {
cc_num.val('');
}
// If we've requested and are waiting for token, prevent any further submit
if (tokenField.val() == 'requested') {
return false; // Prevent any submit processing until token is received
}
// Go ahead and request the token
tokenField.val('requested');
try {
var name = undefined;
if ($(':input[name="panes[billing][billing_first_name]"]').length) {
name = $(':input[name="panes[billing][billing_first_name]"]').val() + " " + $(':input[name="panes[billing][billing_last_name]"]').val();
// Custom styling can be passed to options when creating an Element.
var style = {
base: {
// Add your base input styles here. For example:
fontSize: '24px',
color: "#000000",
iconColor: "blue",
}
if (typeof name === "undefined" && $(':input[name="panes[delivery][delivery_first_name]"]').length) {
name = $(':input[name="panes[delivery][delivery_first_name]"]').val() + " " + $(':input[name="panes[delivery][delivery_last_name]"]').val();
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the #stripe-card-element <div>.
card.mount(stripe_card_element);
// Display errors from stripe
card.addEventListener('change', function(event) {
var displayError = document.getElementById('uc_stripe_messages');
if (event.error) {
displayError.textContent = event.error.message;
console.log(event.error.message)
} else {
displayError.textContent = '';
}
});
submitButton.click(function (e) {
// We must find the various fields again, because they may have been swapped
// in by ajax action of the form.
cc_container = $('.payment-details-credit');
cc_num = cc_container.find(':input[id*="edit-panes-payment-details-cc-numbe"]');
cc_cvv = cc_container.find(':input[id*="edit-panes-payment-details-cc-cv"]');
cc_exp_year = cc_container.find('#edit-panes-payment-details-cc-exp-month');
cc_exp_month = cc_container.find('#edit-panes-payment-details-cc-exp-year');
// If not credit card processing or no payment method field, just let the submit go on
// Also continue if we've received the tokenValue
var paymentMethodField = $("[name='panes[payment-stripe][details][stripe_payment_method]']");
if (!$("div.payment-details-credit").length || !paymentMethodField.length || paymentMethodField.val().indexOf('pm_') == 0) {
return true;
}
var params = {
number: cc_num.val(),
cvc: cc_cvv.val(),
exp_month: $(':input[name="panes[payment][details][cc_exp_month]"]').val(),
exp_year: $(':input[name="panes[payment][details][cc_exp_year]"]').val(),
name: name
};
// If we've requested and are waiting for token, prevent any further submit
if (paymentMethodField.val() == 'requested') {
return false; // Prevent any submit processing until token is received
}
// Translate the Ubercart billing/shipping fields to Stripe values
for (var key in address_field_mapping) {
const prefixes = ['billing', 'delivery'];
for (var i = 0; i < prefixes.length; i++) {
var prefix = prefixes[i];
var uc_field_name = prefix + '_' + address_field_mapping[key];
var location = ':input[name="panes[' + prefix + '][' + uc_field_name + ']"]';
if ($(location).length) {
params[key] = $(location).val();
if ($(location).attr('type') == 'select-one') {
params[key] = $(location + " option:selected").text();
}
break; // break out of billing/shipping loop because we got the info
// Go ahead and request the token
paymentMethodField.val('requested');
try {
stripe.createPaymentMethod('card', card).then(function (response) {
if (response.error) {
// Show the errors on the form
$('#uc_stripe_messages')
.removeClass("hidden")
.text(response.error.message);
$('#edit-stripe-messages').val(response.error.message);
// Make the fields visible again for retry
cc_num
.css('visibility', 'visible')
.val('')
.attr('name', 'panes[payment][details][cc_number]');
cc_cvv
.css('visibility', 'visible')
.val('')
.attr('name', 'panes[payment][details][cc_cvv]');
// Turn off the throbber
$('.ubercart-throbber').remove();
// Remove the bogus copy of the submit button added in uc_cart.js ucSubmitOrderThrobber
submitButton.next().remove();
// And show the hidden original button which has the behavior attached to it.
submitButton.show();
paymentMethodField.val('default'); // Make sure token field set back to default
} else {
// token contains id, last4, and card type
var paymentMethodId = response.paymentMethod.id;
// Insert the token into the form so it gets submitted to the server
paymentMethodField.val(paymentMethodId);
// set cc expiration date received from stripe so that it is available on checkout review
cc_exp_year.val(response.paymentMethod.card.exp_month);
cc_exp_month.val(response.paymentMethod.card.exp_year);
// Since we're now submitting, make sure that uc_credit doesn't
// find values it objects to; after "fixing" set the name back on the
// form element.
// add dummy tweleve 5's and the last 4 of credit card so that last 4 show
cc_num
.css('visibility', 'hidden')
.val('555555555555' + response.paymentMethod.card.last4)
.attr('name', 'panes[payment][details][cc_number]');
cc_cvv
.css('visibility', 'hidden')
.val('999')
.attr('name', 'panes[payment][details][cc_cvv]');
// now actually submit to Drupal. The only "real" things going
// are the token and the expiration date and last 4 of cc
submitButton.click();
}
}
});
} catch (e) {
$('#uc_stripe_messages')
.removeClass("hidden")
.text(e.message);
$('#edit-stripe-messages').val(e.message);
}
Stripe.createToken(params, function (status, response) {
if (response.error) {
// Show the errors on the form
$('#uc_stripe_messages')
.removeClass("hidden")
.text(response.error.message);
$('#edit-stripe-messages').val(response.error.message);
// Make the fields visible again for retry
cc_num
.css('visibility', 'visible')
.val('')
.attr('name', 'panes[payment][details][cc_number]');
cc_cvv
.css('visibility', 'visible')
.val('')
.attr('name', 'panes[payment][details][cc_cvv]');
// Turn off the throbber
$('.ubercart-throbber').remove();
// Remove the bogus copy of the submit button added in uc_cart.js ucSubmitOrderThrobber
submitButton.next().remove();
// And show the hidden original button which has the behavior attached to it.
submitButton.show();
tokenField.val('default'); // Make sure token field set back to default
} else {
// token contains id, last4, and card type
var token = response.id;
// Insert the token into the form so it gets submitted to the server
tokenField.val(token);
// Since we're now submitting, make sure that uc_credit doesn't
// find values it objects to; after "fixing" set the name back on the
// form element.
cc_num
.css('visibility', 'hidden')
.val('555555555555' + response.card.last4)
.attr('name', 'panes[payment][details][cc_number]');
cc_cvv
.css('visibility', 'hidden')
.val('999')
.attr('name', 'panes[payment][details][cc_cvv]');
// now actually submit to Drupal. The only "real" things going
// are the token and the expiration date.
submitButton.click();
}
});
} catch (e) {
$('#uc_stripe_messages')
.removeClass("hidden")
.text(e.message);
$('#edit-stripe-messages').val(e.message);
}
// Prevent processing until we get the token back
return false;
// Prevent processing until we get the token back
return false;
});
});
}
},
};
}(jQuery));

View File

@ -0,0 +1,91 @@
/**
* @file
* uc_stripe.js
*
* Handles all interactions with Stripe on the client side for PCI-DSS compliance
*/
(function ($) {
Drupal.behaviors.uc_stripe_process_payment = {
attach: function (context) {
$('#uc-cart-checkout-review-form, #uc-stripe-authenticate-payment-form', context).once('uc_stripe', function(){
if (Drupal.settings && Drupal.settings.uc_stripe ) {
var apikey = Drupal.settings.uc_stripe.apikey;
var methodId = Drupal.settings.uc_stripe.methodId;
var orderId = Drupal.settings.uc_stripe.orderId
var stripe = Stripe(apikey);
}
var submitButton = $('#edit-submit');
var processed = false;
submitButton.click(function (e) {
if(!processed){
e.preventDefault();
$.ajax({
url: '/uc_stripe/ajax/confirm_payment',
type: "POST",
data: JSON.stringify({ payment_method_id: methodId, order_id: orderId }),
contentType: 'application/json;',
dataType: 'json',
success: function(result){
handleServerResponse(result);
},
error: function(result){
handleServerResponse(result);
}
})
}
});
function handleServerResponse(response) {
if (response.error) {
processed = true;
submitButton.click();
// Show error from server on payment form
} else if (response.requires_action) {
// Use Stripe.js to handle required card action
stripe.handleCardAction(
response.payment_intent_client_secret
).then(function(result) {
if (result.error) {
// Show error in payment form
processed = true;
submitButton.click();
} else {
// The card action has been handled
// The PaymentIntent can be confirmed again on the server
$.ajax({
url: '/uc_stripe/ajax/confirm_payment',
type: 'POST',
data: JSON.stringify({ payment_intent_id: result.paymentIntent.id, order_id: orderId }),
contentType: 'application/json;',
dataType: 'json',
success: function(confirmResult){
return handleServerResponse(confirmResult);
},
error: function(confirmResult){
return handleServerResponse(confirmResult);
},
})
}
});
} else {
// Show success message
processed = true;
submitButton.click();
}
}
});
},
};
}(jQuery));