Revert "Merge pull request #9 from mattbk/7.x-3.1"

This reverts commit 6324febf04, reversing
changes made to fed9880872.
This commit is contained in:
Matt
2019-10-03 21:53:02 -05:00
parent 6324febf04
commit aea105c1ab
4 changed files with 145 additions and 469 deletions

View File

@ -9,185 +9,163 @@
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');
// Load the js reference to these fields so that on the review page var cc_container = $('.payment-details-credit');
// we can input the last 4 and expiration date which is returned to us by stripe paymentMethod call var cc_num = cc_container.find(':input[id*="edit-panes-payment-details-cc-numbe"]');
var cc_container = $('.payment-details-credit'); var cc_cvv = cc_container.find(':input[id*="edit-panes-payment-details-cc-cv"]');
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 // Make sure that when the page is being loaded the token value is reset
// Browser or other caching might do otherwise. // Browser or other caching might do otherwise.
$("[name='panes[payment-stripe][details][stripe_payment_method]']").val('default'); $("[name='panes[payment][details][stripe_token]']").val('default');
// JS must enable the button; otherwise form might disclose cc info. It starts disabled $('span#stripe-nojs-warning').parent().hide();
submitButton.attr('disabled', false);
// When this behavior fires, we can clean the form so it will behave properly, // JS must enable the button; otherwise form might disclose cc info. It starts disabled
// Remove 'name' from sensitive form elements so there's no way they can be submitted. submitButton.attr('disabled', false);
cc_num.removeAttr('name').removeAttr('disabled');
$('div.form-item-panes-payment-details-cc-number').removeClass('form-disabled'); // When this behavior fires, we can clean the form so it will behave properly,
cc_cvv.removeAttr('name').removeAttr('disabled'); // Remove 'name' from sensitive form elements so there's no way they can be submitted.
var cc_val_val = cc_num.val(); cc_num.removeAttr('name').removeAttr('disabled');
if (cc_val_val && cc_val_val.indexOf('Last 4')) { $('div.form-item-panes-payment-details-cc-number').removeClass('form-disabled');
cc_num.val(''); 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') {
return false; // Prevent any submit processing until token is received
}
// Custom styling can be passed to options when creating an Element. // Go ahead and request the token
var style = { tokenField.val('requested');
base: {
// Add your base input styles here. For example: try {
fontSize: '24px', var name = undefined;
color: "#000000",
iconColor: "blue", 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;
} }
// If we've requested and are waiting for token, prevent any further submit var params = {
if (paymentMethodField.val() == 'requested') { number: cc_num.val(),
return false; // Prevent any submit processing until token is received 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
};
// Go ahead and request the token // Translate the Ubercart billing/shipping fields to Stripe values
paymentMethodField.val('requested'); for (var key in address_field_mapping) {
const prefixes = ['billing', 'delivery'];
try { for (var i = 0; i < prefixes.length; i++) {
var prefix = prefixes[i];
stripe.createPaymentMethod('card', card).then(function (response) { var uc_field_name = prefix + '_' + address_field_mapping[key];
var location = ':input[name="panes[' + prefix + '][' + uc_field_name + ']"]';
if (response.error) { if ($(location).length) {
params[key] = $(location).val();
// Show the errors on the form if ($(location).attr('type') == 'select-one') {
$('#uc_stripe_messages') params[key] = $(location + " option:selected").text();
.removeClass("hidden") }
.text(response.error.message); break; // break out of billing/shipping loop because we got the info
$('#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);
} }
// Prevent processing until we get the token back Stripe.createToken(params, function (status, response) {
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));

View File

@ -1,91 +0,0 @@
/**
* @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));

View File

@ -1,62 +0,0 @@
<?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;
}
}

View File

@ -1,149 +0,0 @@
<?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');
}
}