View source
<?php
define('UC_STRIPE_BASIC_STYLES', 0);
define('UC_STRIPE_ADVANCED_STYLES', 1);
module_load_include('inc', 'uc_stripe', 'uc_stripe.mail');
function uc_stripe_libraries_info() {
$libraries['stripe'] = array(
'name' => 'Stripe PHP Library',
'vendor url' => 'http://stripe.com',
'download url' => 'https://github.com/stripe/stripe-php/releases',
'download file url' => 'https://github.com/stripe/stripe-php/archive/v6.38.0.tar.gz',
'version arguments' => array(
'file' => 'VERSION',
'pattern' => '/(\\d+\\.\\d+\\.\\d+)/',
),
'versions' => array(
'6.38.0' => array(
'files' => array(
'php' => array(
'init.php',
),
),
'stripe_api_version' => '2019-05-16',
),
),
);
return $libraries;
}
function uc_stripe_menu() {
$items = array();
$items['uc_stripe/ajax/confirm_payment'] = array(
'access callback' => true,
'page callback' => '_uc_stripe_confirm_payment',
'delivery callback' => 'drupal_json_output',
'type' => MENU_CALLBACK,
);
$items['stripe/authenticate-payment/%'] = array(
'access callback' => true,
'page callback' => 'drupal_get_form',
'page arguments' => array(
'uc_stripe_authenticate_payment_form',
2,
),
'type' => MENU_CALLBACK,
'file' => 'uc_stripe.pages.inc',
);
return $items;
}
function uc_stripe_uc_payment_gateway() {
$gateways = array();
$gateways[] = array(
'id' => 'uc_stripe',
'title' => t('Stripe Gateway'),
'description' => t('Process card payments using Stripe JS.'),
'settings' => 'uc_stripe_settings_form',
'credit' => 'uc_stripe_charge',
);
return $gateways;
}
function uc_stripe_recurring_info() {
$items['uc_stripe'] = array(
'name' => t('Stripe'),
'payment method' => 'credit',
'module' => 'uc_recurring',
'fee handler' => 'uc_stripe',
'process callback' => 'uc_stripe_process',
'renew callback' => 'uc_stripe_renew',
'cancel callback' => 'uc_stripe_cancel',
'own handler' => FALSE,
'menu' => array(
'charge' => UC_RECURRING_MENU_DEFAULT,
'edit' => UC_RECURRING_MENU_DEFAULT,
'cancel' => UC_RECURRING_MENU_DEFAULT,
),
);
return $items;
}
function uc_stripe_form_uc_cart_checkout_review_form_alter(&$form, &$form_state, $form_id) {
if ($form_state['uc_order']->payment_method != 'credit' || uc_credit_default_gateway() != 'uc_stripe') {
return;
}
if (empty($_SESSION['stripe']['payment_method'])) {
$form['actions']['submit']['#type'] = 'hidden';
$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.'));
watchdog('uc_stripe', 'Stripe charge failed for order @order, message: @message', array(
'@order' => $form_state['uc_order']->order_id,
'@message' => 'Payment method not found',
));
drupal_set_message($fail_message, 'error');
return;
}
$stripe_payment_method_id = $_SESSION['stripe']['payment_method'];
$order_id = $form_state['uc_order']->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(
'methodId' => $stripe_payment_method_id,
'apikey' => $apikey,
'orderId' => $order_id,
);
$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';
}
function uc_stripe_form_uc_cart_checkout_form_alter(&$form, &$form_state) {
$form['panes']['payment-stripe']['#attached']['css'][] = array(
'data' => '#payment-stripe-pane { display: none; }',
'type' => 'inline',
);
if (uc_credit_default_gateway() != 'uc_stripe') {
return;
}
$form['panes']['payment-stripe']['#states'] = array(
'visible' => array(
':input[name="panes[payment][payment_method]"]' => array(
'value' => 'credit',
),
),
);
$stripe_payment_form =& $form['panes']['payment-stripe']['details'];
$payment_form =& $form['panes']['payment']['details'];
$stripe_payment_form['stripe_card_element'] = array(
'#prefix' => '<div id="stripe-card-element">',
'#weight' => -10,
'#markup' => '<div class="stripe-warning">' . t('Sorry, for security reasons your card cannot be processed. Please refresh this page and try again. If the problem persists please check that Javascript is enabled your browser.') . '</div>',
'#suffix' => '</div>',
);
if (variable_get('uc_stripe_poweredby', FALSE)) {
$stripe_payment_form['powered_by_stripe'] = array(
'#type' => 'item',
'#markup' => "<a target='_blank' href='http://stripe.com'><img src=" . '/' . drupal_get_path('module', 'uc_stripe') . '/images/solid-dark.svg' . " alt='Powered by Stripe'></a>",
'#weight' => -20,
);
}
$stripe_payment_form['stripe_payment_method'] = array(
'#type' => 'hidden',
'#default_value' => 'default',
'#attributes' => array(
'id' => 'edit-panes-stripe-payment-details-stripe-payment-method',
),
);
if (empty($form['actions']['continue']['#attributes'])) {
$form['actions']['continue']['#attributes'] = array();
}
$form['actions']['continue']['#attributes']['disabled'] = 'disabled';
$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', ''));
if (variable_get('uc_stripe_element_styles_mode', UC_STRIPE_BASIC_STYLES) == UC_STRIPE_ADVANCED_STYLES) {
$element_styles = variable_get('uc_stripe_element_styles_json', '{}');
}
else {
$element_styles = variable_get('uc_stripe_element_styles', 'fontSize: 16px, color: black, iconColor: blue');
if (!empty($element_styles)) {
$element_styles = '{"base":' . json_encode(_uc_stripe_get_element_styles_array()) . '}';
}
else {
$element_styles = '{}';
}
}
$settings = array(
'apikey' => $apikey,
'element_styles' => $element_styles,
);
$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.js';
$form['#attached']['css'][] = drupal_get_path('module', 'uc_stripe') . '/css/uc_stripe.css';
$payment_form['cc_number']['#type'] = 'hidden';
$payment_form['cc_number']['#default_value'] = '';
$payment_form['cc_number']['#attributes']['id'] = 'edit-panes-payment-details-cc-number';
$payment_form['cc_cvv']['#type'] = 'hidden';
$payment_form['cc_cvv']['#default_value'] = '';
$payment_form['cc_cvv']['#attributes']['id'] = 'edit-panes-payment-details-cc-cvv';
$payment_form['cc_exp_year']['#type'] = 'hidden';
$payment_form['cc_exp_year']['#attributes']['id'] = 'edit-panes-payment-details-cc-exp-year';
$min = intval(date('Y'));
$max = intval(date('Y')) + 50;
$default = intval(date('Y'));
$payment_form['cc_exp_year']['#options'] = drupal_map_assoc(range($min, $max));
$payment_form['cc_exp_year']['#default_value'] = $default;
$payment_form['cc_exp_month']['#type'] = 'hidden';
$payment_form['cc_exp_month']['#default_value'] = 1;
$payment_form['cc_exp_month']['#attributes']['id'] = 'edit-panes-payment-details-cc-exp-month';
$form['#submit'][] = 'uc_stripe_checkout_form_customsubmit';
$form['panes']['messages'] = array(
'#markup' => "<div id='uc_stripe_messages' class='messages error hidden'></div>",
);
if (uc_credit_default_gateway() == 'uc_stripe') {
if (variable_get('uc_stripe_testmode', TRUE)) {
$form['panes']['testmode'] = array(
'#prefix' => "<div class='messages' style='background-color:#BEEBBF'>",
'#markup' => t("Test mode is <strong>ON</strong> for the Stripe Payment Gateway. Your card will not be charged. To change this setting, edit the !link", array(
'!link' => l("Stripe settings", "admin/store/settings/payment/method/credit"),
)),
'#suffix' => "</div>",
);
}
}
}
function uc_stripe_uc_order_pane() {
$panes[] = array(
'id' => 'uc_stripe',
'callback' => 'uc_stripe_order_pane_stripe',
'title' => t('Stripe Customer Info'),
'desc' => t("Stripe Information"),
'class' => 'pos-left',
'weight' => 3,
'show' => array(
'view',
'edit',
),
);
return $panes;
}
function uc_stripe_uc_checkout_pane() {
$panes['payment-stripe'] = array(
'callback' => '_uc_stripe_payment_pane_callback',
'title' => t('Payment Information'),
'desc' => t("Accept stripe payment from customer."),
'weight' => 6,
'process' => FALSE,
'collapsible' => FALSE,
);
return $panes;
}
function _uc_stripe_payment_pane_callback($op, $order, $form = NULL, &$form_state = NULL) {
switch ($op) {
case 'view':
$description = t('');
$contents['stripe_card_element'] = array(
'#markup' => '',
);
return array(
'description' => $description,
'contents' => $contents,
);
}
}
function uc_stripe_uc_checkout_complete($order, $account) {
if ($order->payment_method == "credit" && uc_credit_default_gateway() == 'uc_stripe') {
$stripe_payment_id = $_SESSION['stripe']['payment_method'];
$stripe_customer_id = $order->data['stripe_customer_id'];
$loaded_user = user_load($account->uid);
user_save($loaded_user, array(
'data' => array(
'uc_stripe_customer_id' => $stripe_customer_id,
),
));
user_save($loaded_user, array(
'data' => array(
'uc_stripe_payment_id' => $stripe_payment_id,
),
));
}
}
function uc_stripe_order_pane_stripe($op, $order, &$form = NULL, &$form_state = NULL) {
switch ($op) {
case 'view':
$stripe_customer_id = _uc_stripe_get_customer_id($order->uid);
$output = t("Customer ID: ") . $stripe_customer_id;
return array(
'#markup' => $output,
);
default:
return;
}
}
function uc_stripe_settings_form() {
$form['uc_stripe_settings'] = array(
'#type' => 'fieldset',
'#title' => t('Stripe settings'),
);
$form['uc_stripe_settings']['uc_stripe_api_key_test_secret'] = array(
'#type' => 'textfield',
'#title' => t('Test Secret Key'),
'#default_value' => variable_get('uc_stripe_api_key_test_secret', ''),
'#description' => t('Your Development Stripe API Key. Must be the "secret" key, not the "publishable" one.'),
);
$form['uc_stripe_settings']['uc_stripe_api_key_test_publishable'] = array(
'#type' => 'textfield',
'#title' => t('Test Publishable Key'),
'#default_value' => variable_get('uc_stripe_api_key_test_publishable', ''),
'#description' => t('Your Development Stripe API Key. Must be the "publishable" key, not the "secret" one.'),
);
$form['uc_stripe_settings']['uc_stripe_api_key_live_secret'] = array(
'#type' => 'textfield',
'#title' => t('Live Secret Key'),
'#default_value' => variable_get('uc_stripe_api_key_live_secret', ''),
'#description' => t('Your Live Stripe API Key. Must be the "secret" key, not the "publishable" one.'),
);
$form['uc_stripe_settings']['uc_stripe_api_key_live_publishable'] = array(
'#type' => 'textfield',
'#title' => t('Live Publishable Key'),
'#default_value' => variable_get('uc_stripe_api_key_live_publishable', ''),
'#description' => t('Your Live Stripe API Key. Must be the "publishable" key, not the "secret" one.'),
);
$form['uc_stripe_settings']['uc_stripe_element_styles_mode'] = array(
'#type' => 'radios',
'#title' => t('Basic / Advanced Stripe Card Element Styling'),
'#options' => array(
UC_STRIPE_BASIC_STYLES => t('Basic'),
UC_STRIPE_ADVANCED_STYLES => t('Advanced'),
),
'#default_value' => variable_get('uc_stripe_element_styles_mode', UC_STRIPE_BASIC_STYLES),
'#description' => t('Basic styling allows simple modifications while advanced allows greater customization.'),
);
$form['uc_stripe_settings']['uc_stripe_element_styles'] = array(
'#type' => 'textfield',
'#title' => t('Style Settings for Stripe Card Element (Basic)'),
'#description' => t('Enter your style settings as a simple comma-separated list (no quoted commas or pseudo-elements allowed). Example: fontSize: 16px, color: black, iconColor: blue (These styles modify the Stripe "base" styles, see <a target="_blank" href="@stripe-documentation">Stripe documentation</a>)', array(
'@stripe-documentation' => 'https://stripe.com/docs/js/appendix/style',
)),
'#default_value' => variable_get('uc_stripe_element_styles', 'fontSize: 16px, color: black, iconColor: blue'),
'#states' => array(
'visible' => array(
':input[name="uc_stripe_element_styles_mode"]' => array(
'value' => UC_STRIPE_BASIC_STYLES,
),
),
),
);
$form['uc_stripe_settings']['uc_stripe_element_styles_json'] = array(
'#type' => 'textarea',
'#title' => t('Style Settings for Stripe Card Element (Advanced)'),
'#description' => t('Enter a value for the "style" element as a valid JSON-encoded string. Example: {"base":{"fontFamily":"Roboto, Open Sans, Segoe UI, sans-serif","fontSize":"16px","color":"#333333","iconColor":"blue","::placeholder":{"color":"#333333"}}}. Newlines and whitespace are allowed. See <a target="_blank" href="@stripe-documentation">Stripe documentation</a> for all variants.', array(
'@stripe-documentation' => 'https://stripe.com/docs/js/appendix/style',
)),
'#default_value' => variable_get('uc_stripe_element_styles_json', '{}'),
'#states' => array(
'visible' => array(
':input[name="uc_stripe_element_styles_mode"]' => array(
'value' => UC_STRIPE_ADVANCED_STYLES,
),
),
),
);
$email_text = _uc_stripe_get_authentication_required_email_text();
$form['uc_stripe_settings']['uc_stripe_authentication_required_email'] = array(
'#type' => 'textarea',
'#title' => t('Email for Recurring payment authentication'),
'#default_value' => variable_get('uc_stripe_authentication_required_email', $email_text),
'#description' => t('If your site uses recurring payments, some transactions will require the customer to return to the site and authenticate before the subscrption payment can be processed.'),
);
$form['uc_stripe_settings']['uc_stripe_testmode'] = array(
'#type' => 'checkbox',
'#title' => t('Test mode'),
'#description' => 'Testing Mode: Stripe will use the development API key to process the transaction so the card will not actually be charged.',
'#default_value' => variable_get('uc_stripe_testmode', TRUE),
);
$form['uc_stripe_settings']['uc_stripe_poweredby'] = array(
'#type' => 'checkbox',
'#title' => t('Powered by Stripe'),
'#description' => 'Show "powered by Stripe" in checkout.',
'#default_value' => variable_get('uc_stripe_poweredby', FALSE),
);
$form['uc_stripe_settings']['uc_stripe_metadata_titles'] = array(
'#type' => 'checkbox',
'#title' => t('Metadata: Title'),
'#description' => t('Include order item title(s) in Stripe metadata.'),
'#default_value' => variable_get('uc_stripe_metadata_titles', FALSE),
);
$form['uc_stripe_settings']['uc_stripe_metadata_models'] = array(
'#type' => 'checkbox',
'#title' => t('Metadata: Model'),
'#description' => t('Include item model(s) (SKU(s)) in Stripe metadata.'),
'#default_value' => variable_get('uc_stripe_metadata_models', FALSE),
);
return $form;
}
function uc_stripe_form_uc_payment_method_settings_form_alter(&$form, &$form_state) {
if ($form_state['build_info']['args'][0] == 'credit') {
$form['#validate'][] = 'uc_stripe_settings_form_validate';
}
}
function uc_stripe_settings_form_validate($form, &$form_state) {
$elements = array(
'uc_stripe_api_key_test_secret',
'uc_stripe_api_key_test_publishable',
'uc_stripe_api_key_live_secret',
'uc_stripe_api_key_live_publishable',
);
if ($form_state['values']['uc_pg_uc_stripe_enabled']) {
foreach ($elements as $element_name) {
$form_state['values'][$element_name] = _uc_stripe_sanitize_key($form_state['values'][$element_name]);
if (!_uc_stripe_validate_key($form_state['values'][$element_name])) {
form_set_error($element_name, t('@name does not appear to be a valid stripe key', array(
'@name' => $element_name,
)));
}
}
}
if (!empty($form_state['values']['uc_credit_validate_numbers'])) {
form_set_error('uc_credit_validate_numbers', t('When used with Ubercart Stripe, "Validate credit card number at checkout" must be unchecked.'));
}
if ($form_state['values']['uc_stripe_element_styles_mode']) {
$element_styles = $form_state['values']['uc_stripe_element_styles_json'];
if (empty($element_styles)) {
form_set_error('uc_stripe_element_styles_json', t('Empty Style Settings for Stripe Card Element (Advanced) is not a valid JSON. Set to {} or switch off Advanced styling.'));
}
else {
json_decode($element_styles);
if (json_last_error() !== JSON_ERROR_NONE) {
form_set_error('uc_stripe_element_styles_json', t('Style Settings for Stripe Card Element (Advanced) JSON does not validate:') . ' ' . json_last_error_msg());
}
}
}
else {
$element_styles = $form_state['values']['uc_stripe_element_styles'];
if (!empty($element_styles)) {
if (substr($element_styles, -1) == ',') {
form_set_error('uc_stripe_element_styles', t('Stripe Element Styles list should not end with a comma.'));
}
}
}
}
function _uc_stripe_sanitize_key($key) {
$key = trim($key);
$key = check_plain($key);
return $key;
}
function _uc_stripe_validate_key($key) {
$valid = preg_match('/^[a-zA-Z0-9_]+$/', $key);
return $valid;
}
function uc_stripe_checkout_form_customsubmit($form, &$form_state) {
if (!empty($form_state['values']['panes']['payment-stripe']['details']['stripe_payment_method'])) {
$_SESSION['stripe']['payment_method'] = $form_state['values']['panes']['payment-stripe']['details']['stripe_payment_method'];
}
}
function uc_stripe_charge($order_id, $amount, $data) {
global $user;
if (!_uc_stripe_prepare_api()) {
$result = array(
'success' => FALSE,
'comment' => t('Stripe API not found.'),
'message' => t('Stripe API not found. Contact the site administrator.'),
'uid' => $user->uid,
'order_id' => $order_id,
);
return $result;
}
$order = uc_order_load($order_id);
$context = array(
'revision' => 'formatted-original',
'type' => 'amount',
);
$options = array(
'sign' => FALSE,
'thou' => FALSE,
'dec' => FALSE,
'prec' => 2,
);
$amount = uc_currency_format($amount, FALSE, FALSE, FALSE);
if ($amount == 0) {
$result = array(
'success' => TRUE,
'message' => t('Payment of $0 approved'),
'uid' => $user->uid,
'trans_id' => md5(uniqid(rand())),
);
uc_order_comment_save($order_id, $user->uid, $result['message'], 'admin');
return $result;
}
$stripe_customer_id = null;
if (key_exists('stripe_customer_id', $order->data)) {
$stripe_customer_id = $order->data['stripe_customer_id'];
}
try {
if (!key_exists('payment_intent_id', $order->data)) {
throw new Exception('The payment Intent has failed.');
}
if (empty($stripe_customer_id) || is_null($stripe_customer_id)) {
throw new Exception('No customer ID found');
}
if (empty($_SESSION['stripe']['payment_method'])) {
throw new Exception('Token not found');
}
$stripe_payment_method_id = $_SESSION['stripe']['payment_method'];
$params = array(
"amount" => $amount,
"currency" => strtolower($order->currency),
"customer" => $stripe_customer_id,
"description" => t("Order #@order_id", array(
"@order_id" => $order_id,
)),
"metadata" => get_order_metadata($order),
"payment_method" => $stripe_payment_method_id,
"payment_method_types" => [
'card',
],
"confirm" => true,
);
$intent_id = $order->data['payment_intent_id'];
if (!empty($shipping_info)) {
$params['shipping'] = $shipping_info;
\Stripe\PaymentIntent::update($intent_id, [
'shipping' => $shipping_info,
]);
}
$payment_intent = \Stripe\PaymentIntent::retrieve($intent_id);
if ($payment_intent->status != 'succeeded') {
throw new Exception($payment_intent['last_payment_error']['message']);
}
$charge_id = $payment_intent->charges->data[0]['id'];
$formatted_amount = $amount / 100;
$formatted_amount = number_format($formatted_amount, 2);
$result = array(
'success' => TRUE,
'message' => t('Payment of @amount processed successfully, Stripe transaction id @transaction_id.', array(
'@amount' => $formatted_amount,
'@transaction_id' => $charge_id,
)),
'comment' => t('Stripe transaction ID: @transaction_id', array(
'@transaction_id' => $charge_id,
)),
'uid' => $user->uid,
);
uc_order_comment_save($order_id, $user->uid, $result['message'], 'admin');
return $result;
} catch (Exception $e) {
$result = array(
'success' => FALSE,
'comment' => $e
->getCode(),
'message' => t("Stripe Charge Failed for order !order: !message", array(
"!order" => $order_id,
"!message" => $e
->getMessage(),
)),
'uid' => $user->uid,
'order_id' => $order_id,
);
uc_order_comment_save($order_id, $user->uid, $result['message'], 'admin');
watchdog('uc_stripe', 'Stripe charge failed for order @order, message: @message', array(
'@order' => $order_id,
'@message' => $result['message'],
));
return $result;
}
$result = array(
'success' => FALSE,
'comment' => "Stripe Gateway Error",
'message' => "Stripe Gateway Error",
'uid' => $user->uid,
'order_id' => $order_id,
);
uc_order_comment_save($order_id, $user->uid, $result['message'], 'admin');
watchdog('uc_stripe', 'Stripe gateway error for order @order_id', array(
'order_id' => $order_id,
));
return $result;
}
function uc_stripe_renew($order, &$fee) {
try {
_uc_stripe_prepare_api();
$stripe_customer_id = _uc_stripe_get_customer_id($order->uid);
$stripe_payment_id = _uc_stripe_get_payment_id($order->uid);
if (empty($stripe_customer_id)) {
throw new Exception('No stripe customer ID found');
}
$amount = $fee->fee_amount;
$amount = $amount * 100;
$intent_params = array(
'amount' => $amount,
'currency' => strtolower($order->currency),
'payment_method_types' => [
'card',
],
'customer' => $stripe_customer_id,
'off_session' => true,
'confirm' => true,
);
if ($stripe_payment_id) {
$intent_params['payment_method'] = $stripe_payment_id;
}
$idempotency_key = _uc_stripe_create_idempotency_key($order->order_id . $amount . $stripe_payment_id);
drupal_alter('uc_stripe_recurring_intent', $intent_params, $order);
$payment_intent = \Stripe\PaymentIntent::create($intent_params, [
'idempotency_key' => $idempotency_key,
]);
uc_payment_enter($order->order_id, $order->payment_method, $order->order_total, $fee->uid, $payment_intent, "Success");
$formatted_amount = number_format($fee->fee_amount, 2);
$message = t('Card renewal payment of @amount processed successfully.', array(
'@amount' => $formatted_amount,
));
uc_order_comment_save($fee->order_id, $order->uid, $message, 'admin');
return TRUE;
} catch (\Stripe\Error\Card $e) {
if ($e
->getDeclineCode() === 'authentication_required') {
$NOT_COMPLETED = 0;
$hash = drupal_hmac_base64(REQUEST_TIME . $order->order_id, drupal_get_hash_salt() . $stripe_payment_id);
db_insert('uc_stripe_pending_auth')
->fields(array(
'order_id' => $order->order_id,
'completed' => $NOT_COMPLETED,
'rfee_id' => $fee->rfid,
'hash' => $hash,
))
->execute();
$params['body'] = variable_get('uc_stripe_authentication_required_email', _uc_stripe_get_authentication_required_email_text());
$params['user'] = user_load($order->uid);
$params['hash'] = $hash;
drupal_mail('uc_stripe', 'authentication_required', $params['user']->mail, language_default(), $params);
}
$result = array(
'success' => FALSE,
'comment' => $e
->getCode(),
'message' => t("Renewal Failed for order !order: !message", array(
"!order" => $order->order_id,
"!message" => $e
->getMessage(),
)),
);
uc_order_comment_save($order->order_id, $order->uid, $result['message'], 'admin');
watchdog('uc_stripe', 'Renewal failed for order @order_id, code=@code, message: @message', array(
'@order_id' => $order->order_id,
'@code' => $e
->getCode(),
'@message' => $e
->getMessage(),
));
return FALSE;
} catch (Exception $e) {
watchdog('uc_stripe', 'Renewal failed for order @order_id, code=@code, message: @message', array(
'@order_id' => $order->order_id,
'@code' => $e
->getCode(),
'@message' => $e
->getMessage(),
));
return FALSE;
}
}
function uc_stripe_process($order, &$fee) {
return TRUE;
}
function uc_stripe_cancel($order, $op) {
$message = t("Subscription Canceled");
uc_order_comment_save($order->order_id, $order->uid, $message, 'order', 'completed', FALSE);
return TRUE;
}
function _uc_stripe_prepare_api() {
module_load_include('install', 'uc_stripe');
if (!_uc_stripe_load_library()) {
return FALSE;
}
if (!_uc_stripe_check_api_keys()) {
watchdog('uc_stripe', 'Stripe API keys are not configured. Payments cannot be made without them.', array(), WATCHDOG_ERROR);
return FALSE;
}
$secret_key = variable_get('uc_stripe_testmode', TRUE) ? variable_get('uc_stripe_api_key_test_secret', '') : variable_get('uc_stripe_api_key_live_secret', '');
try {
$library = libraries_load('stripe');
\Stripe\Stripe::setApiKey($secret_key);
\Stripe\Stripe::setApiVersion($library['stripe_api_version']);
} catch (Exception $e) {
watchdog('uc_stripe', 'Error setting the Stripe API Key. Payments will not be processed: %error', array(
'%error' => $e
->getMessage(),
));
}
try {
$module_info = system_get_info('module', "uc_stripe");
$uc_stripe_version = is_null($module_info['version']) ? 'dev-unknown' : $module_info['version'];
\Stripe\Stripe::setAppInfo("Drupal Ubercart Stripe", $uc_stripe_version, "https://www.drupal.org/project/uc_stripe");
} catch (Exception $e) {
watchdog('uc_stripe', 'Error setting Stripe plugin information: %error', array(
'%error' => $e
->getMessage(),
));
}
return TRUE;
}
function _uc_stripe_check_api_keys() {
return variable_get('uc_stripe_api_key_live_publishable', FALSE) && variable_get('uc_stripe_api_key_live_secret', FALSE) && variable_get('uc_stripe_api_key_test_publishable', FALSE) && variable_get('uc_stripe_api_key_test_secret', FALSE);
}
function _uc_stripe_get_customer_id($uid) {
$account = user_load($uid);
$id = !empty($account->data['uc_stripe_customer_id']) ? $account->data['uc_stripe_customer_id'] : FALSE;
return $id;
}
function _uc_stripe_get_payment_id($uid) {
$account = user_load($uid);
$id = !empty($account->data['uc_stripe_payment_id']) ? $account->data['uc_stripe_payment_id'] : FALSE;
return $id;
}
function uc_stripe_theme_registry_alter(&$theme_registry) {
if (!empty($theme_registry['uc_payment_method_credit_form'])) {
$theme_registry['uc_payment_method_credit_form']['function'] = 'uc_stripe_uc_payment_method_credit_form';
}
}
function uc_stripe_uc_payment_method_credit_form($form) {
$output .= drupal_render($form['config_error']);
$output .= theme('uc_payment_method_credit_form', $form);
$output .= drupal_render($form['stripe_payment_method']);
$output .= drupal_render($form['dummy_image_load']);
return $output;
}
function _generatePaymentResponse($intent) {
if ($intent->status == 'requires_action' && $intent->next_action->type == 'use_stripe_sdk') {
$response = [
'requires_action' => true,
'payment_intent_client_secret' => $intent->client_secret,
];
}
else {
if ($intent->status == 'succeeded') {
$response = [
'success' => true,
];
}
else {
http_response_code(500);
$response = [
'error' => 'Invalid PaymentIntent status',
];
}
}
return $response;
}
function _uc_stripe_confirm_payment() {
global $user;
$received_json = file_get_contents("php://input", TRUE);
$data = drupal_json_decode($received_json, TRUE);
$order_id = $data['order_id'];
$order = uc_order_load($order_id);
if (!_uc_stripe_prepare_api()) {
$message = 'Stripe API not found.';
watchdog('uc_stripe', 'Error in Stripe API: @message', array(
'@message' => $message,
));
return [
'error' => $message,
];
}
$amount = uc_currency_format($order->order_total, FALSE, FALSE, FALSE);
$stripe_customer_id = False;
$order_has_stripe_id = key_exists('stripe_customer_id', $order->data) ? True : False;
if ($order_has_stripe_id) {
$stripe_customer_id = $order->data['stripe_customer_id'];
}
else {
if ($user->uid != $order->uid) {
$stripe_customer_id = _uc_stripe_get_customer_id($order->uid);
}
else {
$stripe_customer_id = _uc_stripe_get_customer_id($user->uid);
}
}
if ($stripe_customer_id && !_uc_stripe_is_stripe_id_valid($stripe_customer_id)) {
watchdog('uc_stripe', 'Stripe customer: @customer is not valid in this instance of Stripe. A new customer will be created.', array(
'@customer' => $stripe_customer_id,
));
$stripe_customer_id = false;
}
$intent = null;
try {
if (isset($data['payment_method_id'])) {
$payment_method_id = $data['payment_method_id'];
$params = array(
'payment_method' => $payment_method_id,
"description" => t("Order #@order_id", array(
"@order_id" => $order_id,
)),
"metadata" => get_order_metadata($order),
'amount' => $amount,
'currency' => strtolower($order->currency),
'confirmation_method' => 'manual',
'confirm' => true,
'setup_future_usage' => 'off_session',
'save_payment_method' => true,
);
if (!$stripe_customer_id) {
$customer = _uc_stripe_create_stripe_customer($order, $payment_method_id);
if (!$customer) {
$message = 'Customer creation failed.';
return [
'error' => $message,
];
}
$stripe_customer_id = $customer->id;
}
$params['customer'] = $stripe_customer_id;
$idempotency_key = _uc_stripe_create_idempotency_key($order_id . $amount . $payment_method_id);
drupal_alter('uc_stripe_payment_intent', $params, $order);
$intent = \Stripe\PaymentIntent::create($params, [
'idempotency_key' => $idempotency_key,
]);
if (!$order_has_stripe_id) {
$order->data['stripe_customer_id'] = $stripe_customer_id;
}
$order->data['payment_intent_id'] = $intent->id;
uc_order_save($order);
}
if (isset($data['payment_intent_id'])) {
$intent = \Stripe\PaymentIntent::retrieve($data['payment_intent_id']);
$intent
->confirm();
$order->data['payment_intent_id'] = $data['payment_intent_id'];
uc_order_save($order);
}
return _generatePaymentResponse($intent);
} catch (Exception $e) {
watchdog('uc_stripe', 'Payment could not be processed: @message', array(
'@message' => $e
->getMessage(),
));
return [
'error' => $e
->getMessage(),
];
}
}
function _uc_stripe_create_stripe_customer($order, $payment_method_id = NULL) {
$stripe_customer_id = FALSE;
try {
$shipping_info = array();
if (!empty($order->delivery_postal_code)) {
$shipping_info = array(
'name' => @"{$order->delivery_first_name} {$order->delivery_last_name}",
'phone' => @$order->delivery_phone,
);
$delivery_country = uc_get_country_data(array(
'country_id' => $order->delivery_country,
));
if ($delivery_country === FALSE) {
$delivery_country = array(
0 => array(
'country_iso_code_2' => 'US',
),
);
}
$shipping_info['address'] = array(
'city' => @$order->delivery_city,
'country' => @$delivery_country[0]['country_iso_code_2'],
'line1' => @$order->delivery_street1,
'line2' => @$order->delivery_street2,
'postal_code' => @$order->delivery_postal_code,
);
}
$params = array(
'description' => "OrderID: {$order->order_id}",
'email' => "{$order->primary_email}",
);
if (!empty($shipping_info)) {
$params['shipping'] = $shipping_info;
}
$customer = \Stripe\Customer::create($params);
return $customer;
} catch (Exception $e) {
$message = t("Stripe Customer Creation Failed for order !order: !message", array(
"!order" => $order_id,
"!message" => $e
->getMessage(),
));
uc_order_comment_save($order_id, $user->uid, $message, 'admin');
watchdog('uc_stripe', 'Failed stripe customer creation: @message', array(
'@message' => $message,
));
return false;
}
}
function get_order_metadata($order) {
foreach ($order->products as $item) {
$titles[] = $item->title;
$models[] = $item->model;
}
$metadata = array();
if (variable_get('uc_stripe_metadata_models', FALSE) && !empty($models)) {
$metadata['models'] = implode(";", $models);
}
if (variable_get('uc_stripe_metadata_titles', FALSE) && !empty($titles)) {
$metadata['titles'] = implode(";", $titles);
}
return $metadata;
}
function _uc_stripe_is_stripe_id_valid($stripe_id) {
try {
if (!_uc_stripe_prepare_api()) {
$message = 'Stripe API not found.';
watchdog('uc_stripe', 'Error in Stripe API: @message', array(
'@message' => $message,
));
return false;
}
$customer = \Stripe\Customer::retrieve($stripe_id);
return !$customer->deleted;
} catch (Exception $e) {
return false;
}
}
function _uc_stripe_get_element_styles_array() {
$styles = array();
$settings = variable_get('uc_stripe_element_styles', 'fontSize: 16px, color: black, iconColor: blue');
$pairs = explode(',', $settings);
foreach ($pairs as $pair) {
$keyValue = explode(':', $pair);
$key = trim($keyValue[0]);
$value = trim($keyValue[1]);
$styles[$key] = $value;
}
return $styles;
}
function _uc_stripe_create_idempotency_key($key) {
$idempotency_key = hash('sha256', $key);
return $idempotency_key;
}