Update from official release #9
312
js/uc_stripe.js
312
js/uc_stripe.js
@ -8,164 +8,186 @@
|
|||||||
|
|
||||||
Drupal.behaviors.uc_stripe = {
|
Drupal.behaviors.uc_stripe = {
|
||||||
attach: function (context) {
|
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.
|
// Map stripe names to (partial) Ubercart field names; Ubercart names add "billing_" or "shipping_" on the front.
|
||||||
const address_field_mapping = {
|
const address_field_mapping = {
|
||||||
"address_line1": "street1",
|
"address_line1": "street1",
|
||||||
"address_line2": "street2",
|
"address_line2": "street2",
|
||||||
"address_city": "city",
|
"address_city": "city",
|
||||||
"address_state": "zone",
|
"address_state": "zone",
|
||||||
"address_zip": "postal_code",
|
"address_zip": "postal_code",
|
||||||
"address_country": "country"
|
"address_country": "country"
|
||||||
};
|
};
|
||||||
var submitButton = $('.uc-cart-checkout-form #edit-continue');
|
var submitButton = $('.uc-cart-checkout-form #edit-continue');
|
||||||
|
|
||||||
var cc_container = $('.payment-details-credit');
|
// Load the js reference to these fields so that on the review page
|
||||||
var cc_num = cc_container.find(':input[id*="edit-panes-payment-details-cc-numbe"]');
|
// we can input the last 4 and expiration date which is returned to us by stripe paymentMethod call
|
||||||
var cc_cvv = cc_container.find(':input[id*="edit-panes-payment-details-cc-cv"]');
|
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
|
// JS must enable the button; otherwise form might disclose cc info. It starts disabled
|
||||||
// Browser or other caching might do otherwise.
|
submitButton.attr('disabled', false);
|
||||||
$("[name='panes[payment][details][stripe_token]']").val('default');
|
|
||||||
|
|
||||||
$('span#stripe-nojs-warning').parent().hide();
|
// 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.
|
||||||
// JS must enable the button; otherwise form might disclose cc info. It starts disabled
|
cc_num.removeAttr('name').removeAttr('disabled');
|
||||||
submitButton.attr('disabled', false);
|
$('div.form-item-panes-payment-details-cc-number').removeClass('form-disabled');
|
||||||
|
cc_cvv.removeAttr('name').removeAttr('disabled');
|
||||||
// When this behavior fires, we can clean the form so it will behave properly,
|
var cc_val_val = cc_num.val();
|
||||||
// Remove 'name' from sensitive form elements so there's no way they can be submitted.
|
if (cc_val_val && cc_val_val.indexOf('Last 4')) {
|
||||||
cc_num.removeAttr('name').removeAttr('disabled');
|
cc_num.val('');
|
||||||
$('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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we've requested and are waiting for token, prevent any further submit
|
|
||||||
if (tokenField.val() == 'requested') {
|
// Custom styling can be passed to options when creating an Element.
|
||||||
return false; // Prevent any submit processing until token is received
|
var style = {
|
||||||
}
|
base: {
|
||||||
|
// Add your base input styles here. For example:
|
||||||
// Go ahead and request the token
|
fontSize: '24px',
|
||||||
tokenField.val('requested');
|
color: "#000000",
|
||||||
|
iconColor: "blue",
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
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 = {
|
// If we've requested and are waiting for token, prevent any further submit
|
||||||
number: cc_num.val(),
|
if (paymentMethodField.val() == 'requested') {
|
||||||
cvc: cc_cvv.val(),
|
return false; // Prevent any submit processing until token is received
|
||||||
exp_month: $(':input[name="panes[payment][details][cc_exp_month]"]').val(),
|
}
|
||||||
exp_year: $(':input[name="panes[payment][details][cc_exp_year]"]').val(),
|
|
||||||
name: name
|
|
||||||
};
|
|
||||||
|
|
||||||
// Translate the Ubercart billing/shipping fields to Stripe values
|
// Go ahead and request the token
|
||||||
for (var key in address_field_mapping) {
|
paymentMethodField.val('requested');
|
||||||
const prefixes = ['billing', 'delivery'];
|
|
||||||
for (var i = 0; i < prefixes.length; i++) {
|
try {
|
||||||
var prefix = prefixes[i];
|
|
||||||
var uc_field_name = prefix + '_' + address_field_mapping[key];
|
stripe.createPaymentMethod('card', card).then(function (response) {
|
||||||
var location = ':input[name="panes[' + prefix + '][' + uc_field_name + ']"]';
|
|
||||||
if ($(location).length) {
|
if (response.error) {
|
||||||
params[key] = $(location).val();
|
|
||||||
if ($(location).attr('type') == 'select-one') {
|
// Show the errors on the form
|
||||||
params[key] = $(location + " option:selected").text();
|
$('#uc_stripe_messages')
|
||||||
}
|
.removeClass("hidden")
|
||||||
break; // break out of billing/shipping loop because we got the info
|
.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) {
|
// Prevent processing until we get the token back
|
||||||
|
return false;
|
||||||
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;
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}(jQuery));
|
}(jQuery));
|
||||||
|
91
js/uc_stripe_process_payment.js
Normal file
91
js/uc_stripe_process_payment.js
Normal 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));
|
62
uc_stripe.mail.inc
Normal file
62
uc_stripe.mail.inc
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function returns the default off session authention email text.
|
||||||
|
* @return $text - Email text
|
||||||
|
*/
|
||||||
|
function _uc_stripe_get_authentication_required_email_text(){
|
||||||
|
$text = t("Dear [user:name],
|
||||||
|
|
||||||
|
We were unable to process your subscription payment.
|
||||||
|
|
||||||
|
Your financial institution is requesting additional verification before your subscription can be renewed.
|
||||||
|
|
||||||
|
Please visit this link to return to our site and complete the verification step.
|
||||||
|
|
||||||
|
[uc_stripe:verification-link]
|
||||||
|
|
||||||
|
-- [site:name] team
|
||||||
|
|
||||||
|
");
|
||||||
|
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Token callback that adds the authentication link to user mails.
|
||||||
|
*
|
||||||
|
* This function is used by the token_replace() call in uc_stripe_mail() to add
|
||||||
|
* the url to verify payment information
|
||||||
|
*
|
||||||
|
* @param $replacements
|
||||||
|
* An associative array variable containing mappings from token names to
|
||||||
|
* values (for use with strtr()).
|
||||||
|
* @param $data
|
||||||
|
* An associative array of token replacement values.
|
||||||
|
* @param $options
|
||||||
|
* Unused parameter required by the token_replace() function. */
|
||||||
|
function uc_stripe_mail_tokens(&$replacements, $data, $options) {
|
||||||
|
global $base_url;
|
||||||
|
$replacements['[uc_stripe:verification-link]'] = $base_url.'/stripe/authenticate-payment/'.$data['authentication_key'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_mail().
|
||||||
|
*
|
||||||
|
* Send mail and replace token with authenticaion link.
|
||||||
|
*/
|
||||||
|
function uc_stripe_mail($key, &$message, $params) {
|
||||||
|
|
||||||
|
switch ($key) {
|
||||||
|
case 'authentication_required' :
|
||||||
|
|
||||||
|
$message['subject'] = t('Additional Verification Required to Process Subscription.');
|
||||||
|
$variables = array('user' => $params['user'], 'authentication_key' => $params['hash']);
|
||||||
|
|
||||||
|
$message['body'][]= token_replace($params['body'], $variables, array('language' => language_default(), 'callback' => 'uc_stripe_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
149
uc_stripe.pages.inc
Normal file
149
uc_stripe.pages.inc
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_form().
|
||||||
|
*
|
||||||
|
* This form allows the user to authenticate in order for their recurring payment
|
||||||
|
* to be processed.
|
||||||
|
*/
|
||||||
|
function uc_stripe_authenticate_payment_form($form, &$form_state, $hash) {
|
||||||
|
$form = array();
|
||||||
|
|
||||||
|
$pending_order = db_select('uc_stripe_pending_auth', 'u')
|
||||||
|
->fields('u', array('order_id', 'completed', 'rfee_id'))
|
||||||
|
->condition('hash', $hash)
|
||||||
|
->execute()
|
||||||
|
->fetchObject();
|
||||||
|
|
||||||
|
|
||||||
|
if(!$pending_order){
|
||||||
|
$form['error'] = array(
|
||||||
|
'#markup' => t('Sorry, we could not verify your payment details. Please verify the link and try again. Contact support if the problem persists.'),
|
||||||
|
);
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
$order_id = $pending_order->order_id;
|
||||||
|
$completed = $pending_order->completed;
|
||||||
|
$rfee_id = $pending_order->rfee_id;
|
||||||
|
|
||||||
|
if ($completed) {
|
||||||
|
$form['error'] = array(
|
||||||
|
'#markup' => t('This payment has already been verified.'),
|
||||||
|
);
|
||||||
|
return $form;
|
||||||
|
};
|
||||||
|
|
||||||
|
$form['heading'] = array(
|
||||||
|
'#markup' => t('<p>Your financial institution has requested additional verification to process your scheduled payment.</p>'),
|
||||||
|
);
|
||||||
|
|
||||||
|
$form['order_id'] = array(
|
||||||
|
'#type' => 'hidden',
|
||||||
|
'#value' => $order_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
$form['rfee_id'] = array(
|
||||||
|
'#type' => 'hidden',
|
||||||
|
'#value' => $rfee_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
$form['hash'] = array(
|
||||||
|
'#type' => 'hidden',
|
||||||
|
'#value' => $hash,
|
||||||
|
);
|
||||||
|
|
||||||
|
$form['submit'] = array(
|
||||||
|
'#type' => 'submit',
|
||||||
|
'#value' => t('Verify Payment')
|
||||||
|
);
|
||||||
|
|
||||||
|
$order = uc_order_load($order_id);
|
||||||
|
$user = user_load($order->uid);
|
||||||
|
$payment_method_id = _uc_stripe_get_payment_id($user->uid);
|
||||||
|
$stripe_customer_id = _uc_stripe_get_customer_id($user->uid);
|
||||||
|
|
||||||
|
$order_id = $order_id;
|
||||||
|
$apikey = variable_get('uc_stripe_testmode', TRUE) ? check_plain(variable_get('uc_stripe_api_key_test_publishable', '')) : check_plain(variable_get('uc_stripe_api_key_live_publishable', ''));
|
||||||
|
$settings = array('apikey' => $apikey, 'methodId' => $payment_method_id, 'orderId' => $order_id);
|
||||||
|
|
||||||
|
//Attach Stripe v3 JS library and JS for processing payment
|
||||||
|
$form['#attached']['js']['https://js.stripe.com/v3/'] = array('type' => 'external');
|
||||||
|
$form['#attached']['js'][] = array('data' => array('uc_stripe' => $settings), 'type' => 'setting');
|
||||||
|
$form['#attached']['js'][] = drupal_get_path('module', 'uc_stripe') . '/js/uc_stripe_process_payment.js';
|
||||||
|
$form['#attached']['css'][] = drupal_get_path('module', 'uc_stripe') . '/css/uc_stripe.css';
|
||||||
|
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
function uc_stripe_authenticate_payment_form_submit($form, &$form_state){
|
||||||
|
|
||||||
|
$order_id = $form_state['values']['order_id'];
|
||||||
|
$rfee_id = $form_state['values']['rfee_id'];
|
||||||
|
$hash = $form_state['values']['hash'];
|
||||||
|
|
||||||
|
$order = uc_order_load($order_id);
|
||||||
|
$intent_id = $order->data['payment_intent_id'];
|
||||||
|
|
||||||
|
try{
|
||||||
|
_uc_stripe_prepare_api();
|
||||||
|
$payment_intent = \Stripe\PaymentIntent::retrieve($intent_id);
|
||||||
|
|
||||||
|
if ($payment_intent->status != 'succeeded') {
|
||||||
|
throw new Exception('Payment intent failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
$charge_id = $payment_intent->charges->data[0]['id'];
|
||||||
|
$amount = uc_currency_format($order->order_total, FALSE, FALSE, FALSE);
|
||||||
|
|
||||||
|
$formatted_amount = $amount / 100;
|
||||||
|
$formatted_amount = number_format($formatted_amount, 2);
|
||||||
|
|
||||||
|
$message = t('Payment of @amount processed successfully, Stripe transaction id @transaction_id.', array('@amount' => $formatted_amount, '@transaction_id' => $charge_id));
|
||||||
|
$COMPLETED = 1;
|
||||||
|
|
||||||
|
//Set all orders matching the order id and fee id to completed. This is incase
|
||||||
|
// there were multiple attempts to process the subscription.
|
||||||
|
db_update('uc_stripe_pending_auth')
|
||||||
|
->fields(array(
|
||||||
|
'completed' => $COMPLETED,
|
||||||
|
))
|
||||||
|
->condition('order_id', $order_id)
|
||||||
|
->condition('rfee_id', $rfee_id)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$fee = uc_recurring_fee_user_load($rfee_id);
|
||||||
|
uc_payment_enter($order->order_id, $order->payment_method, $order->order_total, $fee->uid, $payment_intent, "Success");
|
||||||
|
|
||||||
|
// Since we have processed the payment here already, we'll temporarily change the fee
|
||||||
|
// handler to the the default uc_recurring fee handler that simply returns TRUE
|
||||||
|
// without any processing.
|
||||||
|
$fee->fee_handler = 'default';
|
||||||
|
$id = uc_recurring_renew($fee);
|
||||||
|
|
||||||
|
// We need to reset the fee handler for this order back to uc_stripe so that
|
||||||
|
// future subscriptions work.
|
||||||
|
$fee = uc_recurring_fee_user_load($fee->rfid);
|
||||||
|
$fee->fee_handler = 'uc_stripe';
|
||||||
|
uc_recurring_fee_user_save($fee);
|
||||||
|
|
||||||
|
uc_order_comment_save($order_id, $order->uid, $message, 'admin');
|
||||||
|
uc_order_comment_save($order_id, $order->uid, $message, 'order', 'completed', FALSE);
|
||||||
|
|
||||||
|
$form_state['redirect'] = '/';
|
||||||
|
drupal_set_message('You have successfully completed your payment');
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
|
||||||
|
$message = t("Stripe Charge Failed for order !order: !message", array(
|
||||||
|
"!order" => $order_id,
|
||||||
|
"!message" => $e->getMessage()
|
||||||
|
));
|
||||||
|
|
||||||
|
uc_order_comment_save($order_id, $order->uid, $message, 'admin');
|
||||||
|
watchdog('uc_stripe', 'Stripe charge failed for order @order, message: @message', array('@order' => $order_id, '@message' => $message));
|
||||||
|
$fail_message = variable_get('uc_credit_fail_message', t('We were unable to process your credit card payment. Please verify your details and try again. If the problem persists, contact us to complete your order.'));
|
||||||
|
drupal_set_message($fail_message, 'error');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user