Add metadata in 7.x-3.x-dev #10

Open
mattbk wants to merge 16 commits from add-metadata-endracing-7.x-3.1 into 7.x-3.x-dev
9 changed files with 371 additions and 1134 deletions
Showing only changes of commit aea105c1ab - Show all commits

View File

@ -8,186 +8,164 @@
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');
// 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');
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"]');
// JS must enable the button; otherwise form might disclose cc info. It starts disabled
submitButton.attr('disabled', false);
// 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');
// 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('');
$('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;
}
// 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 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();
}
};
// 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 (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();
}
// 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
}
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
};
// 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();
// 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
}
});
} 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;
});
});
},
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;
});
}
};
}(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');
}
}