FINAL suepr merge step : added all modules to this super repos
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,12 @@
|
||||
name = 2Checkout
|
||||
description = Processes payments using 2Checkout.com.
|
||||
dependencies[] = uc_payment
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_2checkout module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_2checkout_uninstall() {
|
||||
db_delete('variable')
|
||||
->condition('name', 'uc_2checkout_%', 'LIKE')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unused variable.
|
||||
*/
|
||||
function uc_2checkout_update_7300() {
|
||||
variable_del('uc_2checkout_checkout_button');
|
||||
}
|
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Integrates 2Checkout.com's redirected payment service.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function uc_2checkout_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/store/settings/payment/method/%':
|
||||
if ($arg[5] == '2checkout') {
|
||||
return '<p>' . t('To accept PayPal payments in 2Checkout, please ensure that demo mode is disabled and your store currency is one of USD, AUD, CAD, EUR or GBP.') . '</p>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function uc_2checkout_menu() {
|
||||
$items = array();
|
||||
|
||||
$items['cart/2checkout/complete'] = array(
|
||||
'title' => 'Order complete',
|
||||
'page callback' => 'uc_2checkout_complete',
|
||||
'access callback' => TRUE,
|
||||
'type' => MENU_CALLBACK,
|
||||
'file' => 'uc_2checkout.pages.inc',
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_init().
|
||||
*/
|
||||
function uc_2checkout_init() {
|
||||
global $conf;
|
||||
$conf['i18n_variables'][] = 'uc_2checkout_method_title';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_ucga_display().
|
||||
*/
|
||||
function uc_2checkout_ucga_display() {
|
||||
// Tell UC Google Analytics to display the e-commerce JS on the custom
|
||||
// order completion page for this module.
|
||||
if (arg(0) == 'cart' && arg(1) == '2checkout' && arg(2) == 'complete') {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_payment_method().
|
||||
*
|
||||
* @see uc_payment_method_2checkout()
|
||||
*/
|
||||
function uc_2checkout_uc_payment_method() {
|
||||
$path = base_path() . drupal_get_path('module', 'uc_2checkout');
|
||||
$title = variable_get('uc_2checkout_method_title', t('Credit card on a secure server:'));
|
||||
$title .= '<br />' . theme('image', array(
|
||||
'path' => drupal_get_path('module', 'uc_2checkout') . '/2co_logo.jpg',
|
||||
'attributes' => array('class' => array('uc-2checkout-logo')),
|
||||
));
|
||||
|
||||
$methods['2checkout'] = array(
|
||||
'name' => t('2Checkout'),
|
||||
'title' => $title,
|
||||
'review' => variable_get('uc_2checkout_check', FALSE) ? t('Credit card/eCheck') : t('Credit card'),
|
||||
'desc' => t('Redirect to 2Checkout to pay by credit card or eCheck.'),
|
||||
'callback' => 'uc_payment_method_2checkout',
|
||||
'redirect' => 'uc_2checkout_form',
|
||||
'weight' => 3,
|
||||
'checkout' => TRUE,
|
||||
'no_gateway' => TRUE,
|
||||
);
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds 2Checkout settings to the payment method settings form.
|
||||
*
|
||||
* @see uc_2checkout_uc_payment_method()
|
||||
*/
|
||||
function uc_payment_method_2checkout($op, &$order, $form = NULL, &$form_state = NULL) {
|
||||
switch ($op) {
|
||||
case 'cart-details':
|
||||
$build = array();
|
||||
|
||||
if (variable_get('uc_2checkout_check', FALSE)) {
|
||||
$build['pay_method'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Select your payment type:'),
|
||||
'#default_value' => $_SESSION['pay_method'] == 'CK' ? 'CK' : 'CC',
|
||||
'#options' => array(
|
||||
'CC' => t('Credit card'),
|
||||
'CK' => t('Online check'),
|
||||
),
|
||||
);
|
||||
unset($_SESSION['pay_method']);
|
||||
}
|
||||
|
||||
return $build;
|
||||
|
||||
case 'cart-process':
|
||||
if (isset($form_state['values']['panes']['payment']['details']['pay_method'])) {
|
||||
$_SESSION['pay_method'] = $form_state['values']['panes']['payment']['details']['pay_method'];
|
||||
}
|
||||
return;
|
||||
|
||||
case 'settings':
|
||||
$form['uc_2checkout_sid'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Vendor account number'),
|
||||
'#description' => t('Your 2Checkout vendor account number.'),
|
||||
'#default_value' => variable_get('uc_2checkout_sid', ''),
|
||||
'#size' => 16,
|
||||
);
|
||||
$form['uc_2checkout_secret_word'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Secret word for order verification'),
|
||||
'#description' => t('The secret word entered in your 2Checkout account Look and Feel settings.'),
|
||||
'#default_value' => variable_get('uc_2checkout_secret_word', 'tango'),
|
||||
'#size' => 16,
|
||||
);
|
||||
$form['uc_2checkout_demo'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable demo mode, allowing you to process fake orders for testing purposes.'),
|
||||
'#default_value' => variable_get('uc_2checkout_demo', TRUE),
|
||||
);
|
||||
$form['uc_2checkout_language'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Language preference'),
|
||||
'#description' => t('Adjust language on 2Checkout pages.'),
|
||||
'#options' => array(
|
||||
'en' => t('English'),
|
||||
'sp' => t('Spanish'),
|
||||
),
|
||||
'#default_value' => variable_get('uc_2checkout_language', 'en'),
|
||||
);
|
||||
$form['uc_2checkout_check'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Allow customers to choose to pay by credit card or online check.'),
|
||||
'#default_value' => variable_get('uc_2checkout_check', FALSE),
|
||||
);
|
||||
$form['uc_2checkout_method_title'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Payment method title'),
|
||||
'#default_value' => variable_get('uc_2checkout_method_title', t('Credit card on a secure server:')),
|
||||
);
|
||||
$form['uc_2checkout_checkout_type'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('2Checkout.com checkout type'),
|
||||
'#description' => t('Single page checkout only works for stores selling intangible products using credit card payments.'),
|
||||
'#options' => array(
|
||||
'multi' => t('Multi-page checkout'),
|
||||
'single' => t('Single page checkout'),
|
||||
),
|
||||
'#default_value' => variable_get('uc_2checkout_checkout_type', 'multi'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form to build the submission to 2Checkout.com.
|
||||
*/
|
||||
function uc_2checkout_form($form, &$form_state, $order) {
|
||||
$country = uc_get_country_data(array('country_id' => $order->billing_country));
|
||||
if ($country === FALSE) {
|
||||
$country = array(0 => array('country_iso_code_3' => 'USA'));
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'sid' => variable_get('uc_2checkout_sid', ''),
|
||||
'total' => uc_currency_format($order->order_total, FALSE, FALSE, '.'),
|
||||
'cart_order_id' => $order->order_id,
|
||||
'demo' => variable_get('uc_2checkout_demo', TRUE) ? 'Y' : 'N',
|
||||
'fixed' => 'Y',
|
||||
'lang' => variable_get('uc_2checkout_language', 'en'),
|
||||
'x_receipt_link_url' => url('cart/2checkout/complete/' . uc_cart_get_id(), array('absolute' => TRUE)),
|
||||
'merchant_order_id' => $order->order_id,
|
||||
'pay_method' => isset($_SESSION['pay_method']) ? $_SESSION['pay_method'] : 'CC',
|
||||
'card_holder_name' => drupal_substr($order->billing_first_name . ' ' . $order->billing_last_name, 0, 128),
|
||||
'street_address' => drupal_substr($order->billing_street1, 0, 64),
|
||||
'street_address2' => drupal_substr($order->billing_street2, 0, 64),
|
||||
'city' => drupal_substr($order->billing_city, 0, 64),
|
||||
'state' => uc_get_zone_code($order->billing_zone),
|
||||
'zip' => drupal_substr($order->billing_postal_code, 0, 16),
|
||||
'country' => $country[0]['country_iso_code_3'],
|
||||
'email' => drupal_substr($order->primary_email, 0, 64),
|
||||
'phone' => drupal_substr($order->billing_phone, 0, 16),
|
||||
'id_type' => 1,
|
||||
);
|
||||
|
||||
$i = 0;
|
||||
foreach ($order->products as $product) {
|
||||
$i++;
|
||||
$data['c_prod_' . $i] = $product->model . ',' . $product->qty;
|
||||
$data['c_name_' . $i] = $product->title;
|
||||
$data['c_description_' . $i] = '';
|
||||
$data['c_price_' . $i] = uc_currency_format($product->price, FALSE, FALSE, '.');
|
||||
}
|
||||
|
||||
$form['#action'] = _uc_2checkout_post_url(variable_get('uc_2checkout_checkout_type', 'multi'));
|
||||
|
||||
foreach ($data as $name => $value) {
|
||||
$form[$name] = array('#type' => 'hidden', '#value' => $value);
|
||||
}
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit order'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to obtain 2Checkout URL for a transaction.
|
||||
*/
|
||||
function _uc_2checkout_post_url($type) {
|
||||
switch ($type) {
|
||||
case 'single':
|
||||
return 'https://www.2checkout.com/checkout/spurchase';
|
||||
case 'multi':
|
||||
default:
|
||||
return 'https://www.2checkout.com/2co/buyer/purchase';
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* 2checkout menu items.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Finalizes 2checkout transaction.
|
||||
*/
|
||||
function uc_2checkout_complete($cart_id = 0) {
|
||||
watchdog('2Checkout', 'Receiving new order notification for order !order_id.', array('!order_id' => check_plain($_REQUEST['merchant_order_id'])));
|
||||
|
||||
$order = uc_order_load($_REQUEST['merchant_order_id']);
|
||||
|
||||
if ($order === FALSE || uc_order_status_data($order->order_status, 'state') != 'in_checkout') {
|
||||
return t('An error has occurred during payment. Please contact us to ensure your order has submitted.');
|
||||
}
|
||||
|
||||
$key = $_REQUEST['key'];
|
||||
$order_number = variable_get('uc_2checkout_demo', TRUE) ? 1 : $_REQUEST['order_number'];
|
||||
$valid = md5(variable_get('uc_2checkout_secret_word', 'tango') . $_REQUEST['sid'] . $order_number . $_REQUEST['total']);
|
||||
if (drupal_strtolower($key) != drupal_strtolower($valid)) {
|
||||
uc_order_comment_save($order->order_id, 0, t('Attempted unverified 2Checkout completion for this order.'), 'admin');
|
||||
return MENU_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
if ($_REQUEST['demo'] == 'Y' xor variable_get('uc_2checkout_demo', TRUE)) {
|
||||
watchdog('uc_2checkout', 'The 2checkout payment for order <a href="@order_url">@order_id</a> demo flag was set to %flag, but the module is set to %mode mode.', array(
|
||||
'@order_url' => url('admin/store/orders/' . $order->order_id),
|
||||
'@order_id' => $order->order_id,
|
||||
'%flag' => $_REQUEST['demo'] == 'Y' ? 'Y' : 'N',
|
||||
'%mode' => variable_get('uc_2checkout_demo', TRUE) ? 'Y' : 'N',
|
||||
), WATCHDOG_ERROR);
|
||||
|
||||
if (!variable_get('uc_2checkout_demo', TRUE)) {
|
||||
return MENU_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
$order->billing_street1 = $_REQUEST['street_address'];
|
||||
$order->billing_street2 = $_REQUEST['street_address2'];
|
||||
$order->city = $_REQUEST['city'];
|
||||
$order->billing_postal_code = $_REQUEST['zip'];
|
||||
$order->billing_phone = $_REQUEST['phone'];
|
||||
|
||||
$zone_id = db_query("SELECT zone_id FROM {uc_zones} WHERE zone_code LIKE :code", array(':code' => $_REQUEST['state']))->fetchField();
|
||||
if (!empty($zone_id)) {
|
||||
$order->billing_zone = $zone_id;
|
||||
}
|
||||
|
||||
$country_id = db_query("SELECT country_id FROM {uc_countries} WHERE country_name LIKE :name", array(':name' => $_REQUEST['country']))->fetchField();
|
||||
if (!empty($country_id)) {
|
||||
$order->billing_country = $country_id;
|
||||
}
|
||||
|
||||
// Save changes to order without it's completion.
|
||||
uc_order_save($order);
|
||||
|
||||
if (drupal_strtolower($_REQUEST['email']) !== drupal_strtolower($order->primary_email)) {
|
||||
uc_order_comment_save($order->order_id, 0, t('Customer used a different e-mail address during payment: !email', array('!email' => check_plain($_REQUEST['email']))), 'admin');
|
||||
}
|
||||
|
||||
if ($_REQUEST['credit_card_processed'] == 'Y' && is_numeric($_REQUEST['total'])) {
|
||||
$comment = t('Paid by !type, 2Checkout.com order #!order.', array('!type' => $_REQUEST['pay_method'] == 'CC' ? t('credit card') : t('echeck'), '!order' => check_plain($_REQUEST['order_number'])));
|
||||
uc_payment_enter($order->order_id, '2checkout', $_REQUEST['total'], 0, NULL, $comment);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Your order will be processed as soon as your payment clears at 2Checkout.com.'));
|
||||
uc_order_comment_save($order->order_id, 0, t('!type payment is pending approval at 2Checkout.com.', array('!type' => $_REQUEST['pay_method'] == 'CC' ? t('Credit card') : t('eCheck'))), 'admin');
|
||||
}
|
||||
|
||||
// Empty that cart...
|
||||
uc_cart_empty($cart_id);
|
||||
|
||||
// Add a comment to let sales team know this came in through the site.
|
||||
uc_order_comment_save($order->order_id, 0, t('Order created through website.'), 'admin');
|
||||
|
||||
$build = uc_cart_complete_sale($order, variable_get('uc_new_customer_login', FALSE));
|
||||
|
||||
$page = variable_get('uc_cart_checkout_complete_page', '');
|
||||
|
||||
if (!empty($page)) {
|
||||
drupal_goto($page);
|
||||
}
|
||||
|
||||
return $build;
|
||||
}
|
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Page callbacks for administrative recurring fee operation pages.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Displays a form to update a subscriptions's CC info.
|
||||
*
|
||||
* @see uc_authorizenet_arb_admin_update_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_authorizenet_arb_admin_update_form($form, &$form_state, $rfid) {
|
||||
$order = new stdClass();
|
||||
|
||||
$fee = uc_recurring_fee_load('user', $rfid);
|
||||
|
||||
$form['rfid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $rfid,
|
||||
);
|
||||
$form['description'] = array(
|
||||
'#markup' => '<div>' . t('Subscription ID: @subscription_id', array('@subscription_id' => $fee['data'])) . '</div>',
|
||||
);
|
||||
|
||||
$form['cc_data'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Credit card details'),
|
||||
'#theme' => 'uc_payment_method_credit_form',
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
$form['cc_data'] += uc_payment_method_credit_form(array(), $order);
|
||||
unset($form['cc_data']['cc_policy']);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Update'),
|
||||
'#suffix' => l(t('Cancel'), 'admin/store/orders/recurring'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for uc_authorizenet_arb_admin_update_form().
|
||||
*
|
||||
* @see uc_authorizenet_arb_admin_update_form()
|
||||
*/
|
||||
function uc_authorizenet_arb_admin_update_form_submit($form, &$form_state) {
|
||||
$fee = uc_recurring_fee_load('user', $form_state['values']['rfid']);
|
||||
|
||||
$updates = array(
|
||||
'payment' => array(
|
||||
'creditCard' => array(
|
||||
'cardNumber' => $form_state['values']['cc_data']['cc_number'],
|
||||
'expirationDate' => $form_state['values']['cc_data']['cc_exp_year'] . '-' . $form_state['values']['cc_data']['cc_exp_month'],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$result = uc_authorizenet_arb_update($fee['data'], $updates, $fee['order_id']);
|
||||
|
||||
// If the update was successful...
|
||||
if ($result) {
|
||||
drupal_set_message(t('Subscription data updated at Authorize.Net.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Subscription update failed. See order admin comments for more details.'), 'error');
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'admin/store/orders/recurring';
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a confirm form for canceling a subscription.
|
||||
*
|
||||
* @see uc_authorizenet_arb_admin_cancel_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_authorizenet_arb_admin_cancel_form($form, &$form_state, $rfid) {
|
||||
$form['rfid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $rfid,
|
||||
);
|
||||
|
||||
return confirm_form($form, t('Are you sure you wish to cancel this subscription?'), 'admin/store/orders/recurring', NULL, t('Confirm'), t('Cancel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for uc_authorizenet_arb_admin_cancel_form().
|
||||
*
|
||||
* @see uc_authorizenet_arb_admin_cancel_form()
|
||||
*/
|
||||
function uc_authorizenet_arb_admin_cancel_form_submit($form, &$form_state) {
|
||||
$fee = uc_recurring_fee_load('user', $form_state['values']['rfid']);
|
||||
|
||||
$result = uc_authorizenet_arb_cancel($fee['data'], $fee['order_id'], $fee);
|
||||
|
||||
// If the cancellation was successful...
|
||||
if ($result) {
|
||||
drupal_set_message(t('Subscription canceled through Authorize.Net.'));
|
||||
|
||||
// Set the fee's recurring charges to 0.
|
||||
uc_recurring_fee_cancel($fee['rfid']);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Subscription cancellation failed. See order admin comments for more details.'), 'error');
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'admin/store/orders/recurring';
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the Authorize.net module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allows transaction data to be altered before sending to Authorize.net.
|
||||
*
|
||||
* @param $data
|
||||
* The transaction data as specified by the Authorize.net API.
|
||||
*/
|
||||
function hook_uc_authorizenet_transaction_alter(&$data) {
|
||||
$data['x_description'] = 'Custom Authorize.Net transaction description.';
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
@@ -0,0 +1,13 @@
|
||||
name = Authorize.net
|
||||
description = Processes payments using Authorize.net. Supports AIM and ARB.
|
||||
dependencies[] = uc_payment
|
||||
dependencies[] = uc_credit
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_authorizenet module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function uc_authorizenet_requirements($phase) {
|
||||
$t = get_t();
|
||||
|
||||
$has_curl = function_exists('curl_init');
|
||||
|
||||
$requirements['uc_authorizenet_curl'] = array(
|
||||
'title' => $t('cURL'),
|
||||
'value' => $has_curl ? $t('Enabled') : $t('Not found'),
|
||||
);
|
||||
if (!$has_curl) {
|
||||
$requirements['uc_authorizenet_curl']['severity'] = REQUIREMENT_ERROR;
|
||||
$requirements['uc_authorizenet_curl']['description'] = $t("Authorize.net requires the PHP <a href='!curl_url'>cURL</a> library.", array('!curl_url' => 'http://php.net/manual/en/curl.setup.php'));
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_authorizenet_uninstall() {
|
||||
// Delete related variables all at once.
|
||||
db_delete('variable')
|
||||
->condition('name', 'uc_authnet_%', 'LIKE')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function uc_authorizenet_update_last_removed() {
|
||||
return 3;
|
||||
}
|
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Page callbacks for Authorize.Net's Silent POST feature and user
|
||||
* specific recurring fee operation pages.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Receives a payment notification and handles it appropriately.
|
||||
*/
|
||||
function uc_authorizenet_silent_post() {
|
||||
// Determine if this is an ARB notification or not
|
||||
$arb = (isset($_POST['x_subscription_id']) and isset($_POST['x_subscription_paynum']));
|
||||
|
||||
// Log ARB payment notification, if enabled.
|
||||
if (variable_get('uc_authnet_report_arb_post', FALSE)) {
|
||||
$args = array(
|
||||
'!arb' => $arb ? 'ARB ' : '',
|
||||
'@order_id' => $_POST['x_invoice_num'],
|
||||
'@post' => print_r($_POST, TRUE),
|
||||
);
|
||||
watchdog('uc_authorizenet', '!arbSilent POST received for order @order_id: <pre>@post</pre>', $args);
|
||||
}
|
||||
|
||||
// Decrypt the Auth.Net API login data.
|
||||
$login_data = _uc_authorizenet_login_data();
|
||||
|
||||
// TODO: Modify the MD5 hash to accommodate differences from AIM to ARB.
|
||||
|
||||
// This is an ARB notification.
|
||||
if ($arb) {
|
||||
|
||||
// Compare our expected MD5 Hash against what was received.
|
||||
$md5 = strtoupper(md5($login_data['md5_hash'] . $_POST['x_trans_id'] . $_POST['x_amount']));
|
||||
|
||||
// Post an error message if the MD5 hash does not validate.
|
||||
if ($_POST['x_MD5_Hash'] != $md5) {
|
||||
watchdog('uc_authorizenet', 'Invalid ARB payment notification received.', array(), WATCHDOG_ERROR);
|
||||
}
|
||||
// Otherwise, let other modules act on the data.
|
||||
else {
|
||||
module_invoke_all('uc_auth_arb_payment', $_POST);
|
||||
}
|
||||
}
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a form for customers to update their CC info.
|
||||
*
|
||||
* @see uc_authorizenet_arb_user_update_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_authorizenet_arb_user_update_form($form, &$form_state, $user, $rfid) {
|
||||
$fee = uc_recurring_fee_load('user', $rfid);
|
||||
|
||||
$form['uid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $user->uid,
|
||||
);
|
||||
$form['rfid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $rfid,
|
||||
);
|
||||
$form['description'] = array(
|
||||
'#markup' => '<div>' . t('Recurring fee order ID: @order_id', array('@order_id' => $fee['order_id'])) . '</div>',
|
||||
);
|
||||
|
||||
$form['cc_data'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Credit card details'),
|
||||
'#theme' => 'uc_payment_method_credit_form',
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
$form['cc_data'] += uc_payment_method_credit_form(array(), $order);
|
||||
unset($form['cc_data']['cc_policy']);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Update'),
|
||||
'#suffix' => l(t('Cancel'), 'user/' . $user->uid),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for uc_authorizenet_arb_user_update_form().
|
||||
*
|
||||
* @see uc_authorizenet_arb_user_update_form()
|
||||
*/
|
||||
function uc_authorizenet_arb_user_update_form_submit($form, &$form_state) {
|
||||
$fee = uc_recurring_fee_load('user', $form_state['values']['rfid']);
|
||||
|
||||
$updates = array(
|
||||
'payment' => array(
|
||||
'creditCard' => array(
|
||||
'cardNumber' => $form_state['values']['cc_data']['cc_number'],
|
||||
'expirationDate' => $form_state['values']['cc_data']['cc_exp_year'] . '-' . $form_state['values']['cc_data']['cc_exp_month'],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$result = uc_authorizenet_arb_update($fee['data'], $updates, $fee['order_id']);
|
||||
|
||||
// If the update was successful...
|
||||
if ($result) {
|
||||
drupal_set_message(t('The payment details for that recurring fee have been updated.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('An error has occurred while updating your payment details. Please try again and contact us if you are unable to perform the update.'), 'error');
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'user/' . $form_state['values']['uid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a confirm form for customers to cancel their fees.
|
||||
*
|
||||
* @see uc_authorizenet_arb_user_cancel_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_authorizenet_arb_user_cancel_form($form, &$form_state, $user, $rfid) {
|
||||
$form['uid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $user->uid,
|
||||
);
|
||||
$form['rfid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $rfid,
|
||||
);
|
||||
|
||||
return confirm_form($form, t('Are you sure you wish to cancel this fee?'), 'user/' . $user->uid, t('This action cannot be undone and may result in the termination of subscription services.'), t('Confirm'), t('Cancel'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for uc_authorizenet_arb_user_cancel_form().
|
||||
*
|
||||
* @see uc_authorizenet_arb_user_cancel_form()
|
||||
*/
|
||||
function uc_authorizenet_arb_user_cancel_form_submit($form, &$form_state) {
|
||||
$fee = uc_recurring_fee_load('user', $form_state['values']['rfid']);
|
||||
|
||||
$result = uc_authorizenet_arb_cancel($fee['data'], $fee['order_id'], $fee);
|
||||
|
||||
// If the cancellation was successful...
|
||||
if ($result) {
|
||||
drupal_set_message(t('The recurring fee has been canceled.'));
|
||||
|
||||
// Set the fee's recurring charges to 0.
|
||||
uc_recurring_fee_cancel($fee['rfid']);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('An error has occurred. Please try again and contact us if the problem persists.'), 'error');
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'user/' . $form_state['values']['uid'];
|
||||
}
|
After Width: | Height: | Size: 645 B |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 933 B |
After Width: | Height: | Size: 808 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 6.8 KiB |
@@ -0,0 +1,13 @@
|
||||
name = Test gateway
|
||||
description = Adds a credit card gateway that simulates a successful payment for testing checkout.
|
||||
dependencies[] = uc_payment
|
||||
dependencies[] = uc_credit
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* A dummy payment gateway to use for testing or as an example.
|
||||
*
|
||||
* All payments using this test gateway will succeed, except when:
|
||||
* - Credit card number equals '0000000000000000'. (Note that ANY card number
|
||||
* that fails the Luhn algorithm check performed by uc_credit will not even be
|
||||
* submitted to this gateway).
|
||||
* - CVV equals '000'.
|
||||
* - Credit card is expired.
|
||||
* - Payment amount equals 12.34 in store currency units.
|
||||
* - Customer's billing first name equals 'Fictitious'.
|
||||
* - Customer's billing telephone number equals '8675309'.
|
||||
*/
|
||||
|
||||
/*******************************************************************************
|
||||
* Hook Functions (Ubercart)
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Implements hook_uc_payment_gateway().
|
||||
*
|
||||
* @see test_gateway.module
|
||||
* @see test_gateway_charge()
|
||||
*/
|
||||
function test_gateway_uc_payment_gateway() {
|
||||
$gateways['test_gateway'] = array(
|
||||
'title' => t('Test Gateway'),
|
||||
'description' => t('Process credit card payments through the Test Gateway.'),
|
||||
'credit' => 'test_gateway_charge',
|
||||
);
|
||||
|
||||
return $gateways;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Module and Helper Functions
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Callback function to perform the charge operation.
|
||||
*
|
||||
* @see test_gateway.module
|
||||
* @see test_gateway_uc_payment_gateway()
|
||||
*/
|
||||
function test_gateway_charge($order_id, $amount, $data) {
|
||||
global $user;
|
||||
$order = uc_order_load($order_id);
|
||||
|
||||
// cc_exp_month and cc_exp_year are also validated by
|
||||
// _uc_credit_valid_card_expiration() on the checkout form.
|
||||
$month = $order->payment_details['cc_exp_month'];
|
||||
$year = $order->payment_details['cc_exp_year'];
|
||||
if ($year < 100) {
|
||||
$year = $year + 2000;
|
||||
}
|
||||
|
||||
// Card is expired at 0:00 on the first day of the next month.
|
||||
$expiration_date = mktime(0, 0, 0, $month + 1, 1, $year);
|
||||
|
||||
// Conditions for failure are described in file documentation block above.
|
||||
// All other transactions will succeed.
|
||||
if ($order->payment_details['cc_number'] == '0000000000000000' ||
|
||||
(isset($order->payment_details['cc_cvv']) && $order->payment_details['cc_cvv'] == '000') ||
|
||||
($expiration_date - REQUEST_TIME) <= 0 ||
|
||||
$amount == 12.34 ||
|
||||
$order->billing_first_name == 'Fictitious' ||
|
||||
$order->billing_phone == '8675309' ) {
|
||||
$success = FALSE;
|
||||
}
|
||||
else {
|
||||
$success = TRUE;
|
||||
}
|
||||
|
||||
// Uncomment this line to see the order object. The information for the
|
||||
// payment is in the $order->payment_details array.
|
||||
// drupal_set_message('<pre>' . print_r($order->payment_details, TRUE) . '</pre>');
|
||||
|
||||
if ($success) {
|
||||
$message = t('Credit card charged: !amount', array('!amount' => uc_currency_format($amount)));
|
||||
uc_order_comment_save($order_id, $user->uid, $message, 'admin');
|
||||
}
|
||||
else {
|
||||
$message = t('Credit card charge failed.');
|
||||
uc_order_comment_save($order_id, $user->uid, $message, 'admin');
|
||||
}
|
||||
|
||||
$result = array(
|
||||
'success' => $success,
|
||||
'comment' => t('Card charged, resolution code: 0022548315'),
|
||||
'message' => $success ? t('Credit card payment processed successfully.') : t('Credit card charge failed.'),
|
||||
'uid' => $user->uid,
|
||||
// 'data' => $data,
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Credit card payment method tests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tests credit card payments with the test gateway.
|
||||
*
|
||||
* This class is intended to be subclassed for use in testing other credit
|
||||
* card gateways. Subclasses which test other gateways need to:
|
||||
* - Define getInfo().
|
||||
* - Override setUp(), if necessary, to enable the other gateway and any other
|
||||
* needed modules.
|
||||
* - Override configureGateway() to implement gateway-specific configuration.
|
||||
* No other overrides are necessary, although a subclass may want to add
|
||||
* additional test functions to cover cases not included in this base class.
|
||||
*/
|
||||
class UbercartCreditCardTestCase extends UbercartTestHelper {
|
||||
|
||||
/**
|
||||
* A selection of "test" numbers to use for testing credit card payemnts.
|
||||
* These numbers all pass the Luhn algorithm check and are reserved by
|
||||
* the card issuer for testing purposes.
|
||||
*/
|
||||
protected static $test_cards = array(
|
||||
'378282246310005', // American Express
|
||||
'371449635398431',
|
||||
'370000000000002',
|
||||
'378734493671000', // American Express Corporate
|
||||
'5610591081018250', // Australian BankCard
|
||||
'30569309025904', // Diners Club
|
||||
'38520000023237',
|
||||
'38000000000006', // Carte Blanche
|
||||
'6011111111111117', // Discover
|
||||
'6011000990139424',
|
||||
'6011000000000012',
|
||||
'3530111333300000', // JCB
|
||||
'3566002020360505',
|
||||
'3088000000000017',
|
||||
'5555555555554444', // MasterCard
|
||||
'5105105105105100',
|
||||
'4111111111111111', // Visa
|
||||
'4012888888881881',
|
||||
'4007000000027',
|
||||
'4012888818888',
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Describes this test case.
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Credit cards with Test Gateway',
|
||||
'description' => 'Uses the Test Gateway to ensure credit card processing is functioning.',
|
||||
'group' => 'Ubercart',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements DrupalWebTestCase::setUp().
|
||||
*/
|
||||
public function setUp(array $modules = array()) {
|
||||
$modules += array('uc_payment', 'uc_credit', 'test_gateway');
|
||||
$permissions = array('administer credit cards', 'process credit cards');
|
||||
parent::setUp($modules, $permissions);
|
||||
|
||||
// Need admin permissions in order to change credit card settings.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
// Configure and enable Credit card module and Test gateway.
|
||||
$this->configureCreditCard();
|
||||
$this->configureGateway();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to configure Credit Card payment method settings.
|
||||
*/
|
||||
protected function configureCreditCard() {
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment',
|
||||
array('uc_payment_method_credit_checkout' => TRUE),
|
||||
t('Save configuration')
|
||||
);
|
||||
$this->assertFieldByName(
|
||||
'uc_payment_method_credit_checkout',
|
||||
TRUE,
|
||||
t('Credit card payment method is enabled')
|
||||
);
|
||||
|
||||
// Create key directory, make it readable and writeable.
|
||||
// Putting this under sites/default/files because SimpleTest needs to be
|
||||
// able to create the directory - this is NOT where you'd put the key file
|
||||
// on a live site. On a live site, it should be outside the web root.
|
||||
drupal_mkdir('sites/default/files/simpletest.keys', 0755);
|
||||
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array(
|
||||
'uc_credit_encryption_path' => 'sites/default/files/simpletest.keys',
|
||||
),
|
||||
t('Save configuration')
|
||||
);
|
||||
|
||||
$this->assertFieldByName(
|
||||
'uc_credit_encryption_path',
|
||||
'sites/default/files/simpletest.keys',
|
||||
t('Key file path has been set.')
|
||||
);
|
||||
|
||||
$this->assertTrue(
|
||||
file_exists('sites/default/files/simpletest.keys/' . UC_CREDIT_KEYFILE_NAME),
|
||||
t('Key has been generated and stored.')
|
||||
);
|
||||
$this->pass('Key = ' . uc_credit_encryption_key());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to configure Credit Card gateway.
|
||||
*/
|
||||
protected function configureGateway() {
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array(
|
||||
'uc_payment_credit_gateway' => 'test_gateway',
|
||||
'uc_pg_test_gateway_enabled' => TRUE,
|
||||
),
|
||||
t('Save configuration')
|
||||
);
|
||||
|
||||
$this->assertFieldByName(
|
||||
'uc_pg_test_gateway_enabled',
|
||||
TRUE,
|
||||
t('Test gateway is enabled')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements DrupalWebTestCase::tearDown().
|
||||
*/
|
||||
public function tearDown() {
|
||||
// Cleanup keys directory after test.
|
||||
drupal_unlink('sites/default/files/simpletest.keys/' . UC_CREDIT_KEYFILE_NAME);
|
||||
drupal_rmdir('sites/default/files/simpletest.keys');
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function. Creates a new order.
|
||||
*/
|
||||
protected function createOrder($fields = array()) {
|
||||
$order = uc_order_new();
|
||||
foreach ($fields as $key => $value) {
|
||||
$order->$key = $value;
|
||||
}
|
||||
|
||||
if (empty($order->primary_email)) {
|
||||
$order->primary_email = $this->randomString() . '@example.org';
|
||||
}
|
||||
|
||||
if (!isset($fields['products'])) {
|
||||
$item = clone $this->product;
|
||||
$item->qty = 1;
|
||||
$item->price = $item->sell_price;
|
||||
$item->data = array();
|
||||
$order->products = array($item);
|
||||
}
|
||||
|
||||
$order->order_total = uc_order_get_total($order, TRUE);
|
||||
$order->line_items = uc_order_load_line_items($order, TRUE);
|
||||
uc_order_save($order);
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests security settings configuration.
|
||||
*/
|
||||
public function testSecuritySettings() {
|
||||
// TODO: Still need tests with existing key file
|
||||
// where key file is not readable or doesn't contain a valid key
|
||||
|
||||
// Create key directory, make it readable and writeable.
|
||||
drupal_mkdir('sites/default/files/testkey', 0755);
|
||||
|
||||
// Try to submit settings form without a key file path.
|
||||
// Save current variable, reset to its value when first installed.
|
||||
$temp_variable = variable_get('uc_credit_encryption_path', '');
|
||||
variable_set('uc_credit_encryption_path', '');
|
||||
|
||||
$this->drupalGet('admin/store/settings/payment/method/credit');
|
||||
$this->assertText(t('Credit card security settings must be configured in the security settings tab.'));
|
||||
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array(),
|
||||
t('Save configuration')
|
||||
);
|
||||
$this->assertFieldByName(
|
||||
'uc_credit_encryption_path',
|
||||
t('Not configured.'),
|
||||
t('Key file has not yet been configured.')
|
||||
);
|
||||
// Restore variable setting.
|
||||
variable_set('uc_credit_encryption_path', $temp_variable);
|
||||
|
||||
// Try to submit settings form with an empty key file path.
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array('uc_credit_encryption_path' => ''),
|
||||
t('Save configuration')
|
||||
);
|
||||
$this->assertText('Key path must be specified in security settings tab.');
|
||||
|
||||
// Specify non-existent directory
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array('uc_credit_encryption_path' => 'sites/default/ljkh/asdfasfaaaaa'),
|
||||
t('Save configuration')
|
||||
);
|
||||
$this->assertText('You have specified a non-existent directory.');
|
||||
|
||||
// Next, specify existing directory that's write protected.
|
||||
// Use /dev, as that should never be accessible.
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array('uc_credit_encryption_path' => '/dev'),
|
||||
t('Save configuration')
|
||||
);
|
||||
$this->assertText('Cannot write to directory, please verify the directory permissions.');
|
||||
|
||||
// Next, specify writeable directory, but with excess whitespace
|
||||
// and trailing /
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array('uc_credit_encryption_path' => ' sites/default/files/testkey/ '),
|
||||
t('Save configuration')
|
||||
);
|
||||
// See that the directory has been properly re-written to remove
|
||||
// whitespace and trailing /
|
||||
$this->assertFieldByName(
|
||||
'uc_credit_encryption_path',
|
||||
'sites/default/files/testkey',
|
||||
t('Key file path has been set.')
|
||||
);
|
||||
$this->assertText('Credit card encryption key file generated.');
|
||||
|
||||
// Check that warning about needing key file goes away.
|
||||
$this->assertNoText(t('Credit card security settings must be configured in the security settings tab.'));
|
||||
// Remove key file.
|
||||
drupal_unlink('sites/default/files/testkey/' . UC_CREDIT_KEYFILE_NAME);
|
||||
|
||||
// Finally, specify good directory
|
||||
$this->drupalPost(
|
||||
'admin/store/settings/payment/method/credit',
|
||||
array('uc_credit_encryption_path' => 'sites/default/files/testkey'),
|
||||
t('Save configuration')
|
||||
);
|
||||
$this->assertText('Credit card encryption key file generated.');
|
||||
|
||||
// Test contents - must contain 32-character hexadecimal string.
|
||||
$this->assertTrue(
|
||||
file_exists('sites/default/files/simpletest.keys/' . UC_CREDIT_KEYFILE_NAME),
|
||||
t('Key has been generated and stored.')
|
||||
);
|
||||
$this->assertTrue(
|
||||
preg_match("([0-9a-fA-F]{32})", uc_credit_encryption_key()),
|
||||
t('Valid key detected in key file.')
|
||||
);
|
||||
|
||||
// Cleanup keys directory after test.
|
||||
drupal_unlink('sites/default/files/testkey/' . UC_CREDIT_KEYFILE_NAME);
|
||||
drupal_rmdir('sites/default/files/testkey');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an order can be placed using the test gateway.
|
||||
*/
|
||||
public function testCheckout() {
|
||||
$this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
|
||||
$this->checkout(array(
|
||||
'panes[payment][details][cc_number]' => array_rand(array_flip(self::$test_cards)),
|
||||
'panes[payment][details][cc_cvv]' => mt_rand(100, 999),
|
||||
'panes[payment][details][cc_exp_month]' => mt_rand(1, 12),
|
||||
'panes[payment][details][cc_exp_year]' => mt_rand(date('Y') + 1, 2022),
|
||||
));
|
||||
$this->assertText('Your order is complete!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that expiry date validation functions correctly.
|
||||
*/
|
||||
public function testExpiryDate() {
|
||||
$order = $this->createOrder(array('payment_method' => 'credit'));
|
||||
|
||||
$year = date('Y');
|
||||
$month = date('n');
|
||||
for ($y = $year; $y <= $year + 2; $y++) {
|
||||
for ($m = 1; $m <= 12; $m++) {
|
||||
$edit = array(
|
||||
'amount' => 1,
|
||||
'cc_data[cc_number]' => '4111111111111111',
|
||||
'cc_data[cc_cvv]' => '123',
|
||||
'cc_data[cc_exp_month]' => $m,
|
||||
'cc_data[cc_exp_year]' => $y,
|
||||
);
|
||||
$this->drupalPost('admin/store/orders/' . $order->order_id . '/credit', $edit, 'Charge amount');
|
||||
|
||||
if ($y > $year || $m >= $month) {
|
||||
$this->assertText('The credit card was processed successfully.', t('Card with expiry date @month/@year passed validation.', array('@month' => $m, '@year' => $y)));
|
||||
}
|
||||
else {
|
||||
$this->assertNoText('The credit card was processed successfully.', t('Card with expiry date @month/@year correctly failed validation.', array('@month' => $m, '@year' => $y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,644 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Credit administration menu items.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Credit card settings form.
|
||||
*
|
||||
* @see uc_credit_settings_form_validate()
|
||||
* @see uc_credit_settings_form_submit()
|
||||
*/
|
||||
function uc_credit_settings_form($form, &$form_state) {
|
||||
if (!user_access('administer credit cards')) {
|
||||
$form['notice'] = array(
|
||||
'#markup' => '<div>' . t('You must have access to <b>administer credit cards</b> to adjust these settings.') . '</div>',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
$gateways = _uc_payment_gateway_list('credit');
|
||||
if (!count($gateways)) {
|
||||
$form['notice'] = array(
|
||||
'#markup' => '<div>' . t('Please enable a credit card gateway module for your chosen payment provider.') . '</div>',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
$form['uc_credit'] = array(
|
||||
'#type' => 'vertical_tabs',
|
||||
'#attached' => array(
|
||||
'js' => array(
|
||||
'vertical-tabs' => drupal_get_path('module', 'uc_credit') . '/uc_credit.admin.js',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['cc_basic'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Basic settings'),
|
||||
'#group' => 'uc_credit',
|
||||
);
|
||||
$options = array();
|
||||
foreach ($gateways as $id => $gateway) {
|
||||
$options[$id] = $gateway['title'];
|
||||
}
|
||||
$form['cc_basic']['uc_payment_credit_gateway'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Default gateway'),
|
||||
'#options' => $options,
|
||||
'#default_value' => uc_credit_default_gateway(),
|
||||
);
|
||||
$form['cc_basic']['uc_credit_validate_numbers'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Validate credit card numbers at checkout.'),
|
||||
'#description' => t('Invalid card numbers will show an error message to the user so they can correct it.'),
|
||||
'#default_value' => variable_get('uc_credit_validate_numbers', TRUE),
|
||||
);
|
||||
|
||||
// Form elements that deal specifically with card number security.
|
||||
$form['cc_security'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Security settings'),
|
||||
'#description' => t('You are responsible for the security of your website, including the protection of credit card numbers. Please be aware that choosing some settings in this section may decrease the security of credit card data on your website and increase your liability for damages in the case of fraud.'),
|
||||
'#group' => 'uc_credit',
|
||||
);
|
||||
$form['cc_security']['uc_credit_encryption_path'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Encryption key directory'),
|
||||
'#description' => t('The card type, expiration date and last four digits of the card number are encrypted and stored temporarily while the customer is in the process of checking out.<br /><b>You must enable encryption</b> by following the <a href="!url">encryption instructions</a> in order to accept credit card payments.<br />In short, you must enter the path of a directory outside of your document root where the encryption key may be stored.<br />Relative paths will be resolved relative to the Drupal installation directory.<br />Once this directory is set, you should not change it.', array('!url' => 'http://drupal.org/node/1309226')),
|
||||
'#default_value' => uc_credit_encryption_key() ? variable_get('uc_credit_encryption_path', t('Not configured.')) : t('Not configured.'),
|
||||
);
|
||||
|
||||
// Form elements that deal with the type of data requested at checkout.
|
||||
$form['cc_fields'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Credit card fields'),
|
||||
'#description' => t('Specify what information to collect from customers in addition to the card number.'),
|
||||
'#group' => 'uc_credit',
|
||||
'#weight' => 10,
|
||||
);
|
||||
$form['cc_fields']['uc_credit_cvv_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable CVV text field on checkout form.'),
|
||||
'#description' => t('The CVV is an added security measure on credit cards. On Visa, Mastercard, and Discover cards it is a three digit number, and on AmEx cards it is a four digit number. If your credit card processor or payment gateway requires this information, you should enable this feature here.'),
|
||||
'#default_value' => variable_get('uc_credit_cvv_enabled', TRUE),
|
||||
);
|
||||
$form['cc_fields']['uc_credit_owner_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable card owner text field on checkout form.'),
|
||||
'#default_value' => variable_get('uc_credit_owner_enabled', FALSE),
|
||||
);
|
||||
$form['cc_fields']['uc_credit_start_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable card start date on checkout form.'),
|
||||
'#default_value' => variable_get('uc_credit_start_enabled', FALSE),
|
||||
);
|
||||
$form['cc_fields']['uc_credit_issue_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable card issue number text field on checkout form.'),
|
||||
'#default_value' => variable_get('uc_credit_issue_enabled', FALSE),
|
||||
);
|
||||
$form['cc_fields']['uc_credit_bank_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable issuing bank text field on checkout form.'),
|
||||
'#default_value' => variable_get('uc_credit_bank_enabled', FALSE),
|
||||
);
|
||||
$form['cc_fields']['uc_credit_type_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable card type selection on checkout form.'),
|
||||
'#description' => t('If enabled, specify in the textarea below which card options to populate the select box with.'),
|
||||
'#default_value' => variable_get('uc_credit_type_enabled', FALSE),
|
||||
);
|
||||
$form['cc_fields']['uc_credit_accepted_types'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Card type select box options'),
|
||||
'#description' => t('Enter one card type per line. These fields will populate the card type select box if it is enabled.'),
|
||||
'#default_value' => variable_get('uc_credit_accepted_types', implode("\r\n", array(t('Visa'), t('Mastercard'), t('Discover'), t('American Express')))),
|
||||
);
|
||||
|
||||
// Form elements that deal with card types accepted.
|
||||
$form['cc_fields']['cc_types'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Card types'),
|
||||
'#description' => t('Use the checkboxes to specify which card types you accept for payment. Selected card types will show their icons in the payment method selection list and be used for card number validation.'),
|
||||
);
|
||||
$form['cc_fields']['cc_types']['uc_credit_visa'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Visa'),
|
||||
'#default_value' => variable_get('uc_credit_visa', TRUE),
|
||||
);
|
||||
$form['cc_fields']['cc_types']['uc_credit_mastercard'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Mastercard'),
|
||||
'#default_value' => variable_get('uc_credit_mastercard', TRUE),
|
||||
);
|
||||
$form['cc_fields']['cc_types']['uc_credit_discover'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Discover'),
|
||||
'#default_value' => variable_get('uc_credit_discover', TRUE),
|
||||
);
|
||||
$form['cc_fields']['cc_types']['uc_credit_amex'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('American Express'),
|
||||
'#default_value' => variable_get('uc_credit_amex', TRUE),
|
||||
);
|
||||
|
||||
// Form elements that deal with credit card messages to customers.
|
||||
$form['cc_messages'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Customer messages'),
|
||||
'#description' => t('Here you can alter messages displayed to customers using credit cards.'),
|
||||
'#collapsible' => FALSE,
|
||||
'#group' => 'uc_credit',
|
||||
'#weight' => 10,
|
||||
);
|
||||
$form['cc_messages']['uc_credit_policy'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Credit card payment policy'),
|
||||
'#description' => t('Instructions for customers on the checkout page above the credit card fields.'),
|
||||
'#default_value' => variable_get('uc_credit_policy', t('Your billing information must match the billing address for the credit card entered below or we will be unable to process your payment.')),
|
||||
'#rows' => 3,
|
||||
);
|
||||
$form['cc_messages']['uc_credit_fail_message'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Card processing failure message'),
|
||||
'#description' => t('Error message displayed to customers when an attempted payment fails at checkout.'),
|
||||
'#default_value' => 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.')),
|
||||
);
|
||||
|
||||
$txn_types = array(
|
||||
UC_CREDIT_AUTH_ONLY => t('Authorization only'),
|
||||
UC_CREDIT_AUTH_CAPTURE => t('Authorize and capture immediately'),
|
||||
UC_CREDIT_REFERENCE_SET => t('Set a reference only'),
|
||||
);
|
||||
|
||||
foreach ($gateways as $id => $gateway) {
|
||||
$form['gateways'][$id] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => check_plain($gateway['title']),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#group' => 'uc_credit',
|
||||
'#weight' => 5,
|
||||
);
|
||||
$form['gateways'][$id]['uc_pg_' . $id . '_enabled'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable this payment gateway for use.'),
|
||||
'#default_value' => variable_get('uc_pg_' . $id . '_enabled', TRUE),
|
||||
'#weight' => -10,
|
||||
);
|
||||
|
||||
// Get the transaction types associated with this gateway.
|
||||
$gateway_types = uc_credit_gateway_txn_types($id);
|
||||
$options = array();
|
||||
foreach ($txn_types as $type => $title) {
|
||||
if (in_array($type, $gateway_types)) {
|
||||
$options[$type] = $title;
|
||||
}
|
||||
}
|
||||
$form['gateways'][$id]['uc_pg_' . $id . '_cc_txn_type'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Default credit transaction type'),
|
||||
'#description' => t('Only available transaction types are listed. The default will be used unless an administrator chooses otherwise through the terminal.'),
|
||||
'#options' => $options,
|
||||
'#default_value' => variable_get('uc_pg_' . $id . '_cc_txn_type', UC_CREDIT_AUTH_CAPTURE),
|
||||
'#weight' => -5,
|
||||
);
|
||||
|
||||
if (isset($gateway['settings']) && function_exists($gateway['settings'])) {
|
||||
$gateway_settings = $gateway['settings'](array(), $form_state);
|
||||
if (is_array($gateway_settings)) {
|
||||
$form['gateways'][$id] += $gateway_settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($_POST) && !uc_credit_encryption_key()) {
|
||||
drupal_set_message(t('Credit card security settings must be configured in the security settings tab.'), 'warning');
|
||||
}
|
||||
|
||||
$form['#validate'][] = 'uc_credit_settings_form_validate';
|
||||
$form['#submit'][] = 'uc_credit_settings_form_submit';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the encryption key directory and key file.
|
||||
*
|
||||
* Checks that the encryption key directory has been specified, that it
|
||||
* exists, and is readable. and writeable so
|
||||
*
|
||||
* @see uc_credit_settings_form()
|
||||
* @see uc_credit_settings_form_submit()
|
||||
*/
|
||||
function uc_credit_settings_form_validate($form, &$form_state) {
|
||||
|
||||
// Trim trailing whitespace and any trailing / or \ from the key path name.
|
||||
$key_path = rtrim(trim($form_state['values']['uc_credit_encryption_path']), '/\\');
|
||||
|
||||
// Test to see if a path was entered.
|
||||
if (empty($key_path)) {
|
||||
form_set_error('uc_credit_encryption_path', t('Key path must be specified in security settings tab.'));
|
||||
}
|
||||
|
||||
// Construct complete key file path.
|
||||
$key_file = $key_path . '/' . UC_CREDIT_KEYFILE_NAME;
|
||||
|
||||
// Shortcut - test to see if we already have a usable key file.
|
||||
if (file_exists($key_file)) {
|
||||
if (is_readable($key_file)) {
|
||||
// Test contents - must contain 32-character hexadecimal string.
|
||||
$key = uc_credit_encryption_key();
|
||||
if ($key) {
|
||||
if (!preg_match("([0-9a-fA-F]{32})", $key)) {
|
||||
form_set_error('uc_credit_encryption_path', t('Key file already exists in directory, but it contains an invalid key.'));
|
||||
}
|
||||
else {
|
||||
// Key file exists and is valid, save result of trim() back into
|
||||
// $form_state and proceed to submit handler.
|
||||
$form_state['values']['uc_credit_encryption_path'] = $key_path;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
form_set_error('uc_credit_encryption_path', t('Key file already exists in directory, but is not readable. Please verify the file permissions.'));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if directory exists and is writeable.
|
||||
if (is_dir($key_path)) {
|
||||
// The entered directory is valid and in need of a key file.
|
||||
// Flag this condition for the submit handler.
|
||||
$form_state['uc_credit']['update_cc_encrypt_dir'] = TRUE;
|
||||
|
||||
// Can we open for writing?
|
||||
$file = @fopen($key_path . '/encrypt.test', 'w');
|
||||
if ($file === FALSE) {
|
||||
form_set_error('uc_credit_encryption_path', t('Cannot write to directory, please verify the directory permissions.'));
|
||||
unset($form_state['uc_credit']['update_cc_encrypt_dir']);
|
||||
}
|
||||
else {
|
||||
// Can we actually write?
|
||||
if (@fwrite($file, '0123456789') === FALSE) {
|
||||
form_set_error('uc_credit_encryption_path', t('Cannot write to directory, please verify the directory permissions.'));
|
||||
unset($form_state['uc_credit']['update_cc_encrypt_dir']);
|
||||
fclose($file);
|
||||
}
|
||||
else {
|
||||
// Can we read now?
|
||||
fclose($file);
|
||||
$file = @fopen($key_path . '/encrypt.test', 'r');
|
||||
if ($file === FALSE) {
|
||||
form_set_error('uc_credit_encryption_path', t('Cannot read from directory, please verify the directory permissions.'));
|
||||
unset($form_state['uc_credit']['update_cc_encrypt_dir']);
|
||||
}
|
||||
else {
|
||||
fclose($file);
|
||||
}
|
||||
}
|
||||
unlink($key_path . '/encrypt.test');
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Directory doesn't exist.
|
||||
form_set_error('uc_credit_encryption_path', t('You have specified a non-existent directory.'));
|
||||
}
|
||||
|
||||
// If validation succeeds, save result of trim() back into $form_state.
|
||||
$form_state['values']['uc_credit_encryption_path'] = $key_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the encryption key file if it doesn't already exist.
|
||||
*
|
||||
* @see uc_credit_settings_form()
|
||||
* @see uc_credit_settings_form_validate()
|
||||
*/
|
||||
function uc_credit_settings_form_submit($form, &$form_state) {
|
||||
// Check to see if we need to create a key file.
|
||||
if (isset($form_state['uc_credit']['update_cc_encrypt_dir']) &&
|
||||
$form_state['uc_credit']['update_cc_encrypt_dir'] === TRUE) {
|
||||
|
||||
$key_path = $form_state['values']['uc_credit_encryption_path'];
|
||||
$key_file = $key_path . '/' . UC_CREDIT_KEYFILE_NAME;
|
||||
|
||||
if (!file_exists($key_file)) {
|
||||
if (!$file = fopen($key_file, 'wb')) {
|
||||
drupal_set_message(t('Credit card encryption key file creation failed for file @file. Check your filepath settings and directory permissions.', array('@file' => $key_file)), 'error');
|
||||
watchdog('uc_credit', 'Credit card encryption key file creation failed for file @file. Check your filepath settings and directory permissions.', array('@file' => $key_file), WATCHDOG_ERROR);
|
||||
}
|
||||
else {
|
||||
// Replacement key generation suggested by Barry Jaspan
|
||||
// for increased security.
|
||||
fwrite($file, md5(drupal_get_token(serialize($_REQUEST) . serialize($_SERVER) . REQUEST_TIME)));
|
||||
fclose($file);
|
||||
|
||||
drupal_set_message(t('Credit card encryption key file generated. Card data will now be encrypted.'));
|
||||
watchdog('uc_credit', 'Credit card encryption key file generated. Card data will now be encrypted.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the credit card terminal page.
|
||||
*/
|
||||
function uc_credit_terminal($order) {
|
||||
$build['details']['order_total'] = array('#markup' => '<div><strong>' . t('Order total: @total', array('@total' => uc_currency_format($order->order_total))) . '</strong></div>');
|
||||
$build['details']['balance'] = array('#markup' => '<div><strong>' . t('Balance: @balance', array('@balance' => uc_currency_format(uc_payment_balance($order)))) . '</strong></div>');
|
||||
|
||||
$build['form'] = drupal_get_form('uc_credit_terminal_form', $order);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the credit card terminal form for administrators.
|
||||
*
|
||||
* @see uc_credit_terminal_form_validate()
|
||||
* @see uc_credit_terminal_form_submit()
|
||||
*/
|
||||
function uc_credit_terminal_form($form, &$form_state, $order, $lock_amount = FALSE) {
|
||||
// Get the transaction types available to our default gateway.
|
||||
$types = uc_credit_gateway_txn_types(uc_credit_default_gateway());
|
||||
|
||||
// Put the order ID in the form.
|
||||
$form['order_id'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $order->order_id,
|
||||
);
|
||||
|
||||
$balance = uc_payment_balance($order);
|
||||
|
||||
// Let the administrator set the amount to charge.
|
||||
$form['amount'] = array(
|
||||
'#type' => 'uc_price',
|
||||
'#title' => t('Charge Amount'),
|
||||
'#default_value' => $balance > 0 ? uc_currency_format($balance, FALSE, FALSE, '.') : 0,
|
||||
'#disabled' => $lock_amount,
|
||||
);
|
||||
|
||||
// Build a credit card form.
|
||||
$form['specify_card'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Credit card details'),
|
||||
'#description' => t('Use the available buttons in this fieldset to process with the specified card details.'),
|
||||
);
|
||||
$form['specify_card']['cc_data'] = array(
|
||||
'#tree' => TRUE,
|
||||
'#prefix' => '<div class="payment-details-credit clearfix">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
$form['specify_card']['cc_data'] += uc_payment_method_credit_form(array(), $form_state, $order);
|
||||
unset($form['specify_card']['cc_data']['cc_policy']);
|
||||
|
||||
$form['specify_card']['actions'] = array('#type' => 'actions');
|
||||
|
||||
// If available, let the card be charged now.
|
||||
if (in_array(UC_CREDIT_AUTH_CAPTURE, $types)) {
|
||||
$form['specify_card']['actions']['charge_card'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Charge amount'),
|
||||
);
|
||||
}
|
||||
|
||||
// If available, let the amount be authorized.
|
||||
if (in_array(UC_CREDIT_AUTH_ONLY, $types)) {
|
||||
$form['specify_card']['actions']['authorize_card'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Authorize amount only'),
|
||||
);
|
||||
}
|
||||
|
||||
// If available, create a reference at the gateway.
|
||||
if (in_array(UC_CREDIT_REFERENCE_SET, $types)) {
|
||||
$form['specify_card']['actions']['reference_set'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Set a reference only'),
|
||||
);
|
||||
}
|
||||
|
||||
// If available, create a reference at the gateway.
|
||||
if (in_array(UC_CREDIT_CREDIT, $types)) {
|
||||
$form['specify_card']['actions']['credit_card'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Credit amount to this card'),
|
||||
);
|
||||
}
|
||||
|
||||
// Find any uncaptured authorizations.
|
||||
$options = array();
|
||||
|
||||
if (isset($order->data['cc_txns']['authorizations'])) {
|
||||
foreach ($order->data['cc_txns']['authorizations'] as $auth_id => $data) {
|
||||
if (empty($data['captured'])) {
|
||||
$options[$auth_id] = t('@auth_id - @date - @amount authorized', array('@auth_id' => strtoupper($auth_id), '@date' => format_date($data['authorized'], 'short'), '@amount' => uc_currency_format($data['amount'])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If any authorizations existed...
|
||||
if (!empty($options)) {
|
||||
// Display a fieldset with the authorizations and available action buttons.
|
||||
$form['authorizations'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Prior authorizations'),
|
||||
'#description' => t('Use the available buttons in this fieldset to select and act on a prior authorization. The charge amount specified above will be captured against the authorization listed below. Only one capture is possible per authorization, and a capture for more than the amount of the authorization may result in additional fees to you.'),
|
||||
);
|
||||
|
||||
$form['authorizations']['select_auth'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Select authorization'),
|
||||
'#options' => $options,
|
||||
);
|
||||
|
||||
$form['authorizations']['actions'] = array('#type' => 'actions');
|
||||
|
||||
// If available, capture a prior authorization.
|
||||
if (in_array(UC_CREDIT_PRIOR_AUTH_CAPTURE, $types)) {
|
||||
$form['authorizations']['actions']['auth_capture'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Capture amount to this authorization'),
|
||||
);
|
||||
}
|
||||
|
||||
// If available, void a prior authorization.
|
||||
if (in_array(UC_CREDIT_VOID, $types)) {
|
||||
$form['authorizations']['actions']['auth_void'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Void authorization'),
|
||||
);
|
||||
}
|
||||
|
||||
// Collapse this fieldset if no actions are available.
|
||||
if (!isset($form['authorizations']['actions']['auth_capture']) && !isset($form['authorizations']['actions']['auth_void'])) {
|
||||
$form['authorizations']['#collapsible'] = TRUE;
|
||||
$form['authorizations']['#collapsed'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Find any uncaptured authorizations.
|
||||
$options = array();
|
||||
|
||||
// Log a reference to the order for testing.
|
||||
// $order->data = uc_credit_log_reference($order->order_id, substr(md5(REQUEST_TIME), 0, 16), '4111111111111111');
|
||||
|
||||
if (isset($order->data['cc_txns']['references'])) {
|
||||
foreach ($order->data['cc_txns']['references'] as $ref_id => $data) {
|
||||
$options[$ref_id] = t('@ref_id - @date - (Last 4) @card', array('@ref_id' => strtoupper($ref_id), '@date' => format_date($data['created'], 'short'), '@card' => $data['card']));
|
||||
}
|
||||
}
|
||||
|
||||
// If any references existed...
|
||||
if (!empty($options)) {
|
||||
// Display a fieldset with the authorizations and available action buttons.
|
||||
$form['references'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Customer references'),
|
||||
'#description' => t('Use the available buttons in this fieldset to select and act on a customer reference.'),
|
||||
);
|
||||
|
||||
$form['references']['select_ref'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Select references'),
|
||||
'#options' => $options,
|
||||
);
|
||||
|
||||
$form['references']['actions'] = array('#type' => 'actions');
|
||||
|
||||
// If available, capture a prior references.
|
||||
if (in_array(UC_CREDIT_REFERENCE_TXN, $types)) {
|
||||
$form['references']['actions']['ref_capture'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Charge amount to this reference'),
|
||||
);
|
||||
}
|
||||
|
||||
// If available, remove a previously stored reference.
|
||||
if (in_array(UC_CREDIT_REFERENCE_REMOVE, $types)) {
|
||||
$form['references']['actions']['ref_remove'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Remove reference'),
|
||||
);
|
||||
}
|
||||
|
||||
// If available, remove a previously stored reference.
|
||||
if (in_array(UC_CREDIT_REFERENCE_CREDIT, $types)) {
|
||||
$form['references']['actions']['ref_credit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Credit amount to this reference'),
|
||||
);
|
||||
}
|
||||
|
||||
// Collapse this fieldset if no actions are available.
|
||||
if (!isset($form['references']['actions']['ref_capture']) && !isset($form['references']['actions']['ref_remove']) && !isset($form['references']['actions']['ref_credit'])) {
|
||||
$form['references']['#collapsible'] = TRUE;
|
||||
$form['references']['#collapsed'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
$form['#attached']['css'][] = drupal_get_path('module', 'uc_payment') . '/uc_payment.css';
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation handler for credit terminal form.
|
||||
*
|
||||
* @see uc_credit_terminal_form()
|
||||
* @see uc_credit_terminal_form_submit()
|
||||
*/
|
||||
function uc_credit_terminal_form_validate($form, &$form_state) {
|
||||
if (uc_order_load($form_state['values']['order_id']) === FALSE) {
|
||||
form_set_error('', t('Invalid order ID. Unable to process payment.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for credit terminal form.
|
||||
*
|
||||
* @see uc_credit_terminal_form()
|
||||
* @see uc_credit_terminal_form_validate()
|
||||
*/
|
||||
function uc_credit_terminal_form_submit($form, &$form_state) {
|
||||
// Load the order.
|
||||
$order = uc_order_load($form_state['values']['order_id']);
|
||||
|
||||
// Get the data from the form and replace masked data from the order.
|
||||
$cc_data = $form_state['values']['cc_data'];
|
||||
|
||||
if (strpos($cc_data['cc_number'], t('(Last 4) ')) === 0) {
|
||||
$cc_data['cc_number'] = $order->payment_details['cc_number'];
|
||||
}
|
||||
|
||||
if (isset($cc_data['cc_cvv']) && isset($order->payment_details['cc_cvv'])) {
|
||||
if ($cc_data['cc_cvv'] == str_repeat('-', strlen($cc_data['cc_cvv']))) {
|
||||
$cc_data['cc_cvv'] = $order->payment_details['cc_cvv'];
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the values for use during processing.
|
||||
uc_credit_cache('save', $cc_data, FALSE);
|
||||
|
||||
// Build the data array passed on to the payment gateway.
|
||||
$data = array();
|
||||
|
||||
switch ($form_state['values']['op']) {
|
||||
case t('Charge amount'):
|
||||
$data['txn_type'] = UC_CREDIT_AUTH_CAPTURE;
|
||||
break;
|
||||
|
||||
case t('Authorize amount only'):
|
||||
$data['txn_type'] = UC_CREDIT_AUTH_ONLY;
|
||||
break;
|
||||
|
||||
case t('Set a reference only'):
|
||||
$data['txn_type'] = UC_CREDIT_REFERENCE_SET;
|
||||
break;
|
||||
|
||||
case t('Credit amount to this card'):
|
||||
$data['txn_type'] = UC_CREDIT_CREDIT;
|
||||
break;
|
||||
|
||||
case t('Capture amount to this authorization'):
|
||||
$data['txn_type'] = UC_CREDIT_PRIOR_AUTH_CAPTURE;
|
||||
$data['auth_id'] = $form_state['values']['select_auth'];
|
||||
break;
|
||||
|
||||
case t('Void authorization'):
|
||||
$data['txn_type'] = UC_CREDIT_VOID;
|
||||
$data['auth_id'] = $form_state['values']['select_auth'];
|
||||
break;
|
||||
|
||||
case t('Charge amount to this reference'):
|
||||
$data['txn_type'] = UC_CREDIT_REFERENCE_TXN;
|
||||
$data['ref_id'] = $form_state['values']['select_ref'];
|
||||
break;
|
||||
|
||||
case t('Remove reference'):
|
||||
$data['txn_type'] = UC_CREDIT_REFERENCE_REMOVE;
|
||||
$data['ref_id'] = $form_state['values']['select_ref'];
|
||||
break;
|
||||
|
||||
case t('Credit amount to this reference'):
|
||||
$data['txn_type'] = UC_CREDIT_REFERENCE_CREDIT;
|
||||
$data['ref_id'] = $form_state['values']['select_ref'];
|
||||
}
|
||||
|
||||
$result = uc_payment_process_payment('credit', $form_state['values']['order_id'], $form_state['values']['amount'], $data, TRUE, NULL, FALSE);
|
||||
_uc_credit_save_cc_data_to_order(uc_credit_cache('load'), $form_state['values']['order_id']);
|
||||
|
||||
if ($result) {
|
||||
drupal_set_message(t('The credit card was processed successfully. See the admin comments for more details.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('There was an error processing the credit card. See the admin comments for details.'), 'error');
|
||||
}
|
||||
|
||||
$form_state['redirect'] = 'admin/store/orders/' . $form_state['values']['order_id'];
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @file
|
||||
* Utility functions to display settings summaries on vertical tabs.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
|
||||
Drupal.behaviors.creditAdminFieldsetSummaries = {
|
||||
attach: function (context) {
|
||||
$('fieldset#edit-cc-security', context).drupalSetSummary(function(context) {
|
||||
return Drupal.t('Encryption key path') + ': '
|
||||
+ $('#edit-uc-credit-encryption-path', context).val();
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
@@ -0,0 +1,16 @@
|
||||
name = Credit card
|
||||
description = Enables support for credit card payments at checkout.
|
||||
dependencies[] = uc_store
|
||||
dependencies[] = uc_payment
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Test cases
|
||||
files[] = tests/uc_credit.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_credit module.
|
||||
*
|
||||
* This is mostly legacy code now.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_credit_uninstall() {
|
||||
db_delete('variable')
|
||||
->condition('name', 'uc_credit_%', 'LIKE')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function uc_credit_update_last_removed() {
|
||||
// 7.x-3.0-beta2 and earlier were installed with schema version 0,
|
||||
// which causes update.php to fail.
|
||||
return drupal_get_installed_schema_version('uc_credit') == 0 ? 0 : 6000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove credit card debug mode.
|
||||
*/
|
||||
function uc_credit_update_7000(&$sandbox) {
|
||||
drupal_load('module', 'uc_credit');
|
||||
module_load_include('inc', 'uc_store', 'classes/encrypt');
|
||||
|
||||
if (!isset($sandbox['progress'])) {
|
||||
$sandbox['progress'] = 0;
|
||||
$sandbox['current_order_id'] = 0;
|
||||
$sandbox['max'] = db_query("SELECT COUNT(order_id) FROM {uc_orders} WHERE data LIKE '%cc_data%'")->fetchField();
|
||||
}
|
||||
|
||||
$t = get_t();
|
||||
$limit = 100;
|
||||
$crypt = new UbercartEncryption();
|
||||
$key = uc_credit_encryption_key();
|
||||
|
||||
// Truncate stored data from debug mode.
|
||||
$result = db_query_range("SELECT order_id, data FROM {uc_orders} WHERE order_id > :current AND data LIKE '%cc_data%' ORDER BY order_id", 0, $limit, array(':current' => $sandbox['current_order_id']));
|
||||
while ($order = $result->fetchObject()) {
|
||||
$sandbox['current_order_id'] = $order->order_id;
|
||||
|
||||
// Load up the existing data array.
|
||||
$data = unserialize($order->data);
|
||||
$cc_data = uc_credit_cache('save', $data['cc_data']);
|
||||
|
||||
// Save only some limited, PCI compliant data.
|
||||
$cc_data['cc_number'] = substr($cc_data['cc_number'], -4);
|
||||
unset($cc_data['cc_cvv']);
|
||||
|
||||
// Stuff the serialized and encrypted CC details into the array.
|
||||
$data['cc_data'] = $crypt->encrypt($key, base64_encode(serialize($cc_data)));
|
||||
|
||||
// Save it again.
|
||||
db_update('uc_orders')
|
||||
->fields(array('data' => serialize($data)))
|
||||
->condition('order_id', $order->order_id)
|
||||
->execute();
|
||||
|
||||
$sandbox['progress']++;
|
||||
$sandbox['message'] = $t('Scrubbed credit card data from order @order_id', array('@order_id' => $order->order_id));
|
||||
}
|
||||
|
||||
|
||||
if ($sandbox['progress'] < $sandbox['max']) {
|
||||
$sandbox['#finished'] = min(0.99, $sandbox['progress'] / $sandbox['max']);
|
||||
}
|
||||
else {
|
||||
$sandbox['#finished'] = 1;
|
||||
|
||||
variable_del('uc_credit_checkout_process');
|
||||
variable_del('uc_credit_debug');
|
||||
variable_del('uc_credit_clear_status');
|
||||
variable_del('uc_credit_number_duration');
|
||||
variable_del('uc_credit_number_unit');
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Credit menu items.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prints the contents of the CVV information popup window.
|
||||
*/
|
||||
function uc_credit_cvv_info() {
|
||||
$output = "<!DOCTYPE html>\n";
|
||||
$output .= '<html><head><meta charset="utf-8" /></head><body>';
|
||||
|
||||
$output .= '<b>' . t('What is the CVV?') . '</b><p>' . t('CVV stands for Card Verification Value. This number is used as a security feature to protect you from credit card fraud. Finding the number on your card is a very simple process. Just follow the directions below.') . '</p>';
|
||||
$cc_types = array(
|
||||
'visa' => t('Visa'),
|
||||
'mastercard' => t('MasterCard'),
|
||||
'discover' => t('Discover')
|
||||
);
|
||||
foreach ($cc_types as $id => $type) {
|
||||
if (variable_get('uc_credit_' . $id, TRUE)) {
|
||||
$valid_types[] = $type;
|
||||
}
|
||||
}
|
||||
if (count($valid_types) > 0) {
|
||||
$output .= '<br /><b>' . implode(', ', $valid_types) . ':</b><p>';
|
||||
$output .= theme('image', array(
|
||||
'path' => drupal_get_path('module', 'uc_credit') . '/images/visa_cvv.jpg',
|
||||
'attributes' => array('align' => 'left'),
|
||||
));
|
||||
$output .= t('The CVV for these cards is found on the back side of the card. It is only the last three digits on the far right of the signature panel box.');
|
||||
$output .= '</p>';
|
||||
}
|
||||
|
||||
if (variable_get('uc_credit_amex', TRUE)) {
|
||||
$output .= '<br /><p><b>' . t('American Express') . ':</b><p>';
|
||||
$output .= theme('image', array(
|
||||
'path' => drupal_get_path('module', 'uc_credit') . '/images/amex_cvv.jpg',
|
||||
'attributes' => array('align' => 'left'),
|
||||
));
|
||||
$output .= t('The CVV on American Express cards is found on the front of the card. It is a four digit number printed in smaller text on the right side above the credit card number.');
|
||||
$output .= '</p>';
|
||||
}
|
||||
|
||||
$output .= '<p align="right"><input type="button" onclick="self.close();" value="' . t('Close this window') . '" /></p>';
|
||||
|
||||
$output .= '</body></html>';
|
||||
|
||||
print $output;
|
||||
exit();
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Theme functions for the uc_credit module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Themes the credit card CVV help link.
|
||||
*/
|
||||
function theme_uc_credit_cvv_help($variables) {
|
||||
$output = '<div class="uc-credit-cvv-help">';
|
||||
$output .= theme('image', array('path' => drupal_get_path('module', 'uc_credit') . '/images/info.png'));
|
||||
$output .= ' ' . l(t("What's the CVV?"), 'cart/checkout/credit/cvv_info', array('attributes' => array(
|
||||
'onclick' => "window.open(this.href, 'CVV_Info', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=480,height=460'); return false;",
|
||||
)));
|
||||
$output .= '</div>';
|
||||
|
||||
return $output;
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
name = CyberSource
|
||||
description = Processes payments using the CyberSource Silent Order POST and Hosted Order Page services.
|
||||
dependencies[] = uc_payment
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Class definitions
|
||||
files[] = uc_cybersource.soap.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_cybersource module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function uc_cybersource_requirements($phase) {
|
||||
$t = get_t();
|
||||
|
||||
$has_curl = function_exists('curl_init');
|
||||
$has_dom = class_exists('DOMDocument');
|
||||
$has_soap = class_exists('SoapClient');
|
||||
|
||||
// Valid methods are 'soap' and 'post'. Defaults here to 'post' on install.
|
||||
$method = variable_get('uc_cybersource_method', 'post');
|
||||
|
||||
// Using SOAP.
|
||||
if ($method == 'soap') {
|
||||
$requirements['uc_cybersource_soap_and_dom'] = array(
|
||||
'title' => $t('SOAP and DOM'),
|
||||
'value' => $has_soap && $has_dom ? $t('Enabled') : $t('Not found'),
|
||||
);
|
||||
if (!$has_soap || !$has_dom) {
|
||||
$requirements['uc_cybersource_soap_and_dom']['severity'] = REQUIREMENT_ERROR;
|
||||
$requirements['uc_cybersource_soap_and_dom']['description'] = $t("CyberSource's SOAP Toolkit API requires the PHP <a href='!soap_url'>SOAP</a> and <a href='!dom_url'>DOM</a> libraries.", array('!soap_url' => 'http://php.net/manual/en/soap.setup.php', '!dom_url' => 'http://php.net/manual/en/dom.setup.php'));
|
||||
}
|
||||
}
|
||||
|
||||
// Using POST with cURL.
|
||||
elseif ($method == 'post') {
|
||||
$requirements['uc_cybersource_curl'] = array(
|
||||
'title' => $t('cURL'),
|
||||
'value' => $has_curl ? $t('Enabled') : $t('Not found'),
|
||||
);
|
||||
if (!$has_curl) {
|
||||
$requirements['uc_cybersource_curl']['severity'] = REQUIREMENT_ERROR;
|
||||
$requirements['uc_cybersource_curl']['description'] = $t("CyberSource's Silent Order POST requires the PHP <a href='!curl_url'>cURL</a> library.", array('!curl_url' => 'http://php.net/manual/en/curl.setup.php'));
|
||||
}
|
||||
}
|
||||
|
||||
// We need HOP.php if we're using the post method and also the Hosted Order
|
||||
// page, which is a payment method rather than a gateway.
|
||||
if ($method != 'soap') {
|
||||
require_once('uc_cybersource.module');
|
||||
$has_cybersource_hop = uc_cybersource_hop_include();
|
||||
$requirements['uc_cybersource'] = array(
|
||||
'title' => t('CyberSource HOP.php'),
|
||||
'value' => $has_cybersource_hop ? $t('Enabled') : $t('Not found'),
|
||||
);
|
||||
if (!$has_cybersource_hop) {
|
||||
$requirements['uc_cybersource']['description'] = t('For instructions on how to generate this file, please refer to <a href="http://www.cybersource.com/support_center/implementation/downloads/hosted_order_page/">CyberSource\'s Hosted Order Pages Documentation</a>, specifically the "Downloading Security Scripts" in Chapter 2 of the <a href="http://apps.cybersource.com/library/documentation/sbc/HOP_UG/html/">HOP User\'s Guide</a>.');
|
||||
$severity = $phase == 'install' ? REQUIREMENT_INFO : REQUIREMENT_ERROR;
|
||||
$requirements['uc_cybersource']['severity'] = $severity;
|
||||
}
|
||||
else {
|
||||
$requirements['uc_cybersource']['severity'] = REQUIREMENT_OK;
|
||||
$requirements['uc_cybersource']['description'] = t('The HOP.php library is readable.');
|
||||
}
|
||||
}
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_cybersource_uninstall() {
|
||||
// Delete related variables all at once.
|
||||
db_delete('variable')
|
||||
->condition(db_or()
|
||||
->condition('name', 'uc_cybersource_%', 'LIKE')
|
||||
->condition('name', 'cs_ship_from_%', 'LIKE')
|
||||
)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function uc_cybersource_schema() {
|
||||
$schema['uc_payment_cybersource_hop_post'] = array(
|
||||
'fields' => array(
|
||||
'order_id' => array(
|
||||
'description' => 'The order ID as provided by the store.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'request_id' => array(
|
||||
'description' => 'Unique id assigned by CyberSource that identifies payment request.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'request_token' => array(
|
||||
'description' => 'Verification token associated with the request ID.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'reconciliation_id' => array(
|
||||
'description' => 'Reference number generated by CyberSource that you use to reconcile your CyberSource reports with your processor reports.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'gross' => array(
|
||||
'description' => 'The approved payment amount from CyberSource.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'decision' => array(
|
||||
'description' => 'CyberSource decision for payment request.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'reason_code' => array(
|
||||
'description' => 'A code for decision.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'payer_email' => array(
|
||||
'description' => 'The e-mail address of the buyer.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'received' => array(
|
||||
'description' => 'The IPN receipt timestamp.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function uc_cybersource_update_last_removed() {
|
||||
return 2;
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines a class used for communicating with CyberSource via SOAP.
|
||||
*
|
||||
* Provided by Acquia, Commercially supported Drupal - http://acquia.com
|
||||
*/
|
||||
|
||||
class CyberSourceSoapClient extends SoapClient {
|
||||
function __construct($wsdl, $options = NULL) {
|
||||
parent::__construct($wsdl, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the UsernameToken information in the outgoing request.
|
||||
*/
|
||||
function __doRequest($request, $location, $action, $version) {
|
||||
$login = _uc_cybersource_soap_login_data();
|
||||
|
||||
$soapHeader = '<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><wsse:Security SOAP-ENV:mustUnderstand="1"><wsse:UsernameToken><wsse:Username>' . $login['merchant_id'] . '</wsse:Username><wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">' . $login['transaction_key'] . '</wsse:Password></wsse:UsernameToken></wsse:Security></SOAP-ENV:Header>';
|
||||
|
||||
$requestDOM = new DOMDocument('1.0');
|
||||
$soapHeaderDOM = new DOMDocument('1.0');
|
||||
|
||||
try {
|
||||
$requestDOM->loadXML($request);
|
||||
$soapHeaderDOM->loadXML($soapHeader);
|
||||
$node = $requestDOM->importNode($soapHeaderDOM->firstChild, TRUE);
|
||||
$requestDOM->firstChild->insertBefore($node, $requestDOM->firstChild->firstChild);
|
||||
$request = $requestDOM->saveXML();
|
||||
}
|
||||
catch (DOMException $e) {
|
||||
die('Error adding UsernameToken: ' . $e->code);
|
||||
}
|
||||
|
||||
return parent::__doRequest($request, $location, $action, $version);
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
The Google Checkout module has been removed from Ubercart.
|
||||
|
||||
As per https://support.google.com/checkout/sell/answer/3080449,
|
||||
Google Checkout is no longer in operation as of 20 November 2013 and
|
||||
can no longer be used as a payment method. Therefore, we've removed
|
||||
the uc_google_checkout module entirely.
|
||||
|
||||
A skeleton module has been left in place to allow you to UNINSTALL
|
||||
uc_google_checkout from any site where you had it running. Be sure
|
||||
to follow the three steps in https://drupal.org/node/2145671 to
|
||||
completely uninstall the uc_google_checkout module from your site.
|
||||
You may delete the ubercart/uc_google_checkout directory and all its
|
||||
contents after you competely uninstall it.
|
@@ -0,0 +1,14 @@
|
||||
name = Google Checkout
|
||||
description = This module is obsolete and CANNOT be installed. Uninstall hooks remain so you can remove this module if you previously had it installed.
|
||||
dependencies[] = uc_cart
|
||||
dependencies[] = uc_payment
|
||||
dependencies[] = uc_quote
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_google_checkout module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_google_checkout_uninstall() {
|
||||
db_update('uc_order_statuses')
|
||||
->fields(array(
|
||||
'locked' => 0,
|
||||
))
|
||||
->condition(db_or()
|
||||
->condition('order_status_id', 'in_google_checkout')
|
||||
->condition('order_status_id', 'chargeable')
|
||||
)
|
||||
->execute();
|
||||
|
||||
db_delete('variable')
|
||||
->condition('name', 'uc_google_checkout_%', 'LIKE')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function uc_google_checkout_requirements($phase) {
|
||||
$t = get_t();
|
||||
|
||||
$requirements['uc_google_checkout'] = array(
|
||||
'title' => $t('Google Checkout'),
|
||||
'description' => $t('Google Checkout is no longer in operation. This module cannot be installed, only uninstalled. If you already have it installed, you must uninstall it. Follow the instructions in the module\'s <a href="@readme">README.txt</a>', array('@readme' => '/' . drupal_get_path('module', 'uc_google_checkout') . '/README.txt')),
|
||||
'severity' => REQUIREMENT_ERROR,
|
||||
);
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function uc_google_checkout_schema() {
|
||||
$schema = array();
|
||||
|
||||
$schema['uc_gc_products'] = array(
|
||||
'description' => 'Stores Google Checkout information for products.',
|
||||
'fields' => array(
|
||||
'vid' => array(
|
||||
'description' => 'The {uc_products}.vid.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'nid' => array(
|
||||
'description' => 'The {uc_products}.nid.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'gc_salable' => array(
|
||||
'description' => 'A flag indicating whether the product can be sold with Google Checkout. 1 => Yes. 0 => No.',
|
||||
'type' => 'int',
|
||||
'size' => 'tiny',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 1,
|
||||
),
|
||||
),
|
||||
'primary key' => array('vid'),
|
||||
'foreign keys' => array(
|
||||
'uc_products' => array(
|
||||
'table' => 'uc_products',
|
||||
'columns' => array(
|
||||
'nid' => 'nid',
|
||||
'vid' => 'vid',
|
||||
),
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
$schema['uc_gc_orders'] = array(
|
||||
'description' => 'Stores Google Checkout orders information.',
|
||||
'fields' => array(
|
||||
'order_id' => array(
|
||||
'description' => 'The {uc_orders}.order_id.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'gc_order_number' => array(
|
||||
'description' => 'The Google Checkout order number.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '0',
|
||||
),
|
||||
'financial_state' => array(
|
||||
'description' => 'The order financial state.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => 'REVIEWING',
|
||||
),
|
||||
'fulfillment_state' => array(
|
||||
'description' => 'The order fulfillment state.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => 'NEW',
|
||||
),
|
||||
'gc_total' => array(
|
||||
'description' => 'The order total according to Google Checkout.',
|
||||
'type' => 'numeric',
|
||||
'precision' => 16,
|
||||
'scale' => 5,
|
||||
'not null' => TRUE,
|
||||
'default' => 0.0,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'gc_order_number' => array(array('gc_order_number', 20)),
|
||||
),
|
||||
'primary key' => array('order_id'),
|
||||
'foreign keys' => array(
|
||||
'uc_orders' => array(
|
||||
'table' => 'uc_orders',
|
||||
'columns' => array('order_id' => 'order_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['uc_gc_taxes'] = array(
|
||||
'description' => 'Stores tax information for Google Checkout.',
|
||||
'fields' => array(
|
||||
'zone' => array(
|
||||
'description' => 'The 2-letter state abberviation.',
|
||||
'type' => 'varchar',
|
||||
'length' => 2,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'rate' => array(
|
||||
'description' => 'The tax rate.',
|
||||
'type' => 'float',
|
||||
'not null' => TRUE,
|
||||
'default' => 0.0,
|
||||
),
|
||||
'tax_shipping' => array(
|
||||
'description' => 'A flag indicating whether shipping costs are taxed.',
|
||||
'type' => 'int',
|
||||
'size' => 'tiny',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'primary key' => array('zone'),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Ubercart payment related tests
|
||||
*/
|
||||
|
||||
class UbercartPaymentPaneTestCase extends UbercartTestHelper {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Payment checkout pane',
|
||||
'description' => 'Ensures that the payment pane functions properly during checkout.',
|
||||
'group' => 'Ubercart',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides DrupalWebTestCase::setUp().
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp(array('uc_payment', 'uc_payment_pack'));
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies checkout page presents all enabled payment methods.
|
||||
*/
|
||||
public function testPaymentMethodOptions() {
|
||||
// No payment methods.
|
||||
variable_set('uc_payment_method_check_checkout', FALSE);
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertText('Checkout cannot be completed without any payment methods enabled. Please contact an administrator to resolve the issue.');
|
||||
|
||||
// Single payment method.
|
||||
variable_set('uc_payment_method_check_checkout', TRUE);
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertNoText('Select a payment method from the following options.');
|
||||
$this->assertFieldByXPath("//input[@name='panes[payment][payment_method]' and @disabled='disabled']");
|
||||
|
||||
// Multiple payment methods.
|
||||
variable_set('uc_payment_method_other_checkout', TRUE);
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertText('Select a payment method from the following options.');
|
||||
$this->assertNoFieldByXPath("//input[@name='panes[payment][payment_method]' and @disabled='disabled']");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests operation of uc_payment_show_order_total_preview variable.
|
||||
*/
|
||||
public function testOrderTotalPreview() {
|
||||
variable_set('uc_payment_show_order_total_preview', TRUE);
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertText('Order total:');
|
||||
|
||||
variable_set('uc_payment_show_order_total_preview', FALSE);
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertNoText('Order total:');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests free orders.
|
||||
*/
|
||||
public function testFreeOrders() {
|
||||
$free_product = $this->createProduct(array('sell_price' => 0));
|
||||
variable_set('uc_payment_method_check_checkout', TRUE);
|
||||
|
||||
// Check that paid products cannot be purchased for free.
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertText('Check or money order');
|
||||
$this->assertNoText('No payment required');
|
||||
$this->assertNoText('Subtotal: $0.00');
|
||||
|
||||
// Check that a mixture of free and paid products cannot be purchased for free.
|
||||
$this->drupalPost('node/' . $free_product->nid, array(), t('Add to cart'));
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertText('Check or money order');
|
||||
$this->assertNoText('No payment required');
|
||||
$this->assertNoText('Subtotal: $0.00');
|
||||
|
||||
// Check that free products can be purchased successfully with no payment.
|
||||
$this->drupalPost('cart', array(), t('Remove'));
|
||||
$this->drupalPost('cart', array(), t('Remove'));
|
||||
$this->drupalPost('node/' . $free_product->nid, array(), t('Add to cart'));
|
||||
$this->drupalGet('cart/checkout');
|
||||
$this->assertNoText('Check or money order');
|
||||
$this->assertText('No payment required');
|
||||
$this->assertText('Subtotal: $0.00');
|
||||
|
||||
// Check that this is the only available payment method.
|
||||
$this->assertNoText('Select a payment method from the following options.');
|
||||
$this->assertFieldByXPath("//input[@name='panes[payment][payment_method]' and @disabled='disabled']");
|
||||
}
|
||||
}
|
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Payment administration menu items.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Displays an overview of the available payment methods.
|
||||
*
|
||||
* @see theme_uc_payment_methods_table()
|
||||
*/
|
||||
function uc_payment_methods_form($form, &$form_state) {
|
||||
$methods = _uc_payment_method_list();
|
||||
|
||||
$form['pmtable'] = array(
|
||||
'#theme' => 'uc_payment_method_table',
|
||||
);
|
||||
|
||||
foreach ($methods as $id => $method) {
|
||||
$form['pmtable'][$id]['uc_payment_method_' . $id . '_checkout'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => check_plain($method['name']),
|
||||
'#default_value' => variable_get('uc_payment_method_' . $id . '_checkout', $method['checkout']),
|
||||
);
|
||||
$form['pmtable'][$id]['uc_payment_method_' . $id . '_weight'] = array(
|
||||
'#type' => 'weight',
|
||||
'#default_value' => variable_get('uc_payment_method_' . $id . '_weight', $method['weight']),
|
||||
'#attributes' => array('class' => array('uc-payment-method-weight')),
|
||||
);
|
||||
|
||||
if (empty($method['no_gateway'])) {
|
||||
$gateways = _uc_payment_gateway_list($id, TRUE);
|
||||
$options = array();
|
||||
foreach ($gateways as $gateway_id => $gateway) {
|
||||
$options[$gateway_id] = $gateway['title'];
|
||||
}
|
||||
if ($options) {
|
||||
$form['pmtable'][$id]['uc_payment_method_' . $id . '_checkout']['#title'] .= ' (' . t('includes %gateways', array('%gateways' => implode(', ', $options))) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
$links = array();
|
||||
$null = NULL;
|
||||
$method_settings = $method['callback']('settings', $null, array(), $form_state);
|
||||
if (is_array($method_settings)) {
|
||||
$links['settings'] = array(
|
||||
'title' => t('settings'),
|
||||
'href' => 'admin/store/settings/payment/method/' . $id,
|
||||
);
|
||||
}
|
||||
|
||||
$links['conditions'] = array(
|
||||
'title' => t('conditions'),
|
||||
'href' => 'admin/store/settings/payment/manage/uc_payment_method_' . $id,
|
||||
);
|
||||
|
||||
$form['pmtable'][$id]['settings'] = array(
|
||||
'#theme' => 'links',
|
||||
'#links' => $links,
|
||||
'#attributes' => array('class' => array('links', 'inline')),
|
||||
);
|
||||
}
|
||||
|
||||
return system_settings_form($form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Themes the table that displays available payment methods.
|
||||
*
|
||||
* @see uc_payment_methods_form()
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_uc_payment_method_table($variables) {
|
||||
$form = $variables['form'];
|
||||
|
||||
drupal_add_tabledrag('uc-payment-methods', 'order', 'sibling', 'uc-payment-method-weight');
|
||||
|
||||
$header = array(t('Payment method'), t('List position'), t('Operations'));
|
||||
|
||||
$rows = array();
|
||||
foreach (element_children($form) as $method) {
|
||||
$row = array(
|
||||
drupal_render($form[$method]['uc_payment_method_' . $method . '_checkout']),
|
||||
drupal_render($form[$method]['uc_payment_method_' . $method . '_weight']),
|
||||
drupal_render($form[$method]['settings']),
|
||||
);
|
||||
|
||||
$rows[] = array(
|
||||
'data' => $row,
|
||||
'class' => array('draggable'),
|
||||
);
|
||||
}
|
||||
|
||||
return theme('table', array(
|
||||
'header' => $header,
|
||||
'rows' => $rows,
|
||||
'attributes' => array('id' => 'uc-payment-methods'),
|
||||
'empty' => t('No payment methods are available. Modules providing payment methods must first be enabled on the !modules administration page under the "Ubercart - payment" fieldset.', array('!modules' => l(t('Modules'), 'admin/modules'))),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays settings for a single payment method.
|
||||
*/
|
||||
function uc_payment_method_settings_form($form, &$form_state, $method_id) {
|
||||
$callback = _uc_payment_method_data($method_id, 'callback');
|
||||
$null = NULL;
|
||||
$form = $callback('settings', $null, array(), $form_state);
|
||||
return system_settings_form($form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a list of payments attached to an order.
|
||||
*
|
||||
* @see uc_payment_by_order_form_validate()
|
||||
* @see uc_payment_by_order_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_payment_by_order_form($form, &$form_state, $order) {
|
||||
$form['#attached']['css'][] = drupal_get_path('module', 'uc_payment') . '/uc_payment.css';
|
||||
|
||||
$total = $order->order_total;
|
||||
$payments = uc_payment_load_payments($order->order_id);
|
||||
|
||||
$form['order_total'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Order total'),
|
||||
'#theme' => 'uc_price',
|
||||
'#price' => $total,
|
||||
);
|
||||
$form['payments'] = tapir_get_table('uc_payments_table');
|
||||
$form['payments']['#weight'] = 10;
|
||||
|
||||
if ($payments !== FALSE) {
|
||||
foreach ($payments as $payment) {
|
||||
$form['payments'][$payment->receipt_id]['received'] = array(
|
||||
'#markup' => format_date($payment->received, 'custom', variable_get('date_format_uc_store', 'm/d/Y') . '<b\r />H:i:s'),
|
||||
);
|
||||
$form['payments'][$payment->receipt_id]['user'] = array(
|
||||
'#markup' => theme('uc_uid', array('uid' => $payment->uid)),
|
||||
);
|
||||
$form['payments'][$payment->receipt_id]['method'] = array(
|
||||
'#markup' => ($payment->method == '') ? t('Unknown') : $payment->method,
|
||||
);
|
||||
$form['payments'][$payment->receipt_id]['amount'] = array(
|
||||
'#theme' => 'uc_price',
|
||||
'#price' => $payment->amount,
|
||||
);
|
||||
$total -= $payment->amount;
|
||||
$form['payments'][$payment->receipt_id]['balance'] = array(
|
||||
'#theme' => 'uc_price',
|
||||
'#price' => $total,
|
||||
);
|
||||
$form['payments'][$payment->receipt_id]['comment'] = array(
|
||||
'#markup' => ($payment->comment == '') ? '-' : filter_xss_admin($payment->comment),
|
||||
);
|
||||
if (user_access('delete payments')) {
|
||||
$action_value = l(t('Delete'), 'admin/store/orders/' . $order->order_id . '/payments/'
|
||||
. $payment->receipt_id . '/delete');
|
||||
}
|
||||
else {
|
||||
$action_value = '-';
|
||||
}
|
||||
$form['payments'][$payment->receipt_id]['action'] = array(
|
||||
'#markup' => $action_value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$form['balance'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Current balance'),
|
||||
'#theme' => 'uc_price',
|
||||
'#price' => $total,
|
||||
);
|
||||
$form['order_id'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $order->order_id,
|
||||
);
|
||||
|
||||
if (user_access('manual payments')) {
|
||||
$form['payments']['new']['received'] = array(
|
||||
'#type' => 'date',
|
||||
'#default_value' => array(
|
||||
'month' => format_date(REQUEST_TIME, 'custom', 'n'),
|
||||
'day' => format_date(REQUEST_TIME, 'custom', 'j'),
|
||||
'year' => format_date(REQUEST_TIME, 'custom', 'Y'),
|
||||
),
|
||||
);
|
||||
$form['payments']['new']['user'] = array(
|
||||
'#markup' => '-',
|
||||
);
|
||||
$methods = _uc_payment_method_list();
|
||||
foreach ($methods as $id => $method) {
|
||||
$options[$id] = $method['name'];
|
||||
}
|
||||
$form['payments']['new']['method'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Method'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $options,
|
||||
);
|
||||
$form['payments']['new']['amount'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Amount'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 6,
|
||||
);
|
||||
$form['payments']['new']['balance'] = array(
|
||||
'#markup' => '-',
|
||||
);
|
||||
$form['payments']['new']['comment'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Comment'),
|
||||
'#title_display' => 'invisible',
|
||||
'#size' => 32,
|
||||
'#maxlength' => 256,
|
||||
);
|
||||
$form['payments']['new']['action'] = array('#type' => 'actions');
|
||||
$form['payments']['new']['action']['action'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Enter'),
|
||||
);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation for uc_payment_by_order_form().
|
||||
*
|
||||
* @see uc_payment_by_order_form()
|
||||
* @see uc_payment_by_order_form_submit()
|
||||
*/
|
||||
function uc_payment_by_order_form_validate($form, &$form_state) {
|
||||
if (!is_numeric($form_state['values']['payments']['new']['amount'])) {
|
||||
form_set_error('payments][new][amount', t('You must enter a number for the amount.'));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for uc_payment_by_order_form().
|
||||
*
|
||||
* @see uc_payment_by_order_form()
|
||||
* @see uc_payment_by_order_form_validate()
|
||||
*/
|
||||
function uc_payment_by_order_form_submit($form, &$form_state) {
|
||||
global $user;
|
||||
|
||||
$payment = $form_state['values']['payments']['new'];
|
||||
$received = strtotime($payment['received']['year'] . '-' . $payment['received']['month'] . '-' . $payment['received']['day'] . ' 00:00:00');
|
||||
|
||||
// If the value entered is today, use the exact timestamp instead
|
||||
$startofday = mktime(0, 0, 0);
|
||||
|
||||
if ($received == $startofday) {
|
||||
$received = REQUEST_TIME;
|
||||
}
|
||||
|
||||
uc_payment_enter($form_state['values']['order_id'], $payment['method'], $payment['amount'], $user->uid, '', $payment['comment'], $received);
|
||||
|
||||
drupal_set_message(t('Payment entered.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirmation form to delete a payment from an order.
|
||||
*
|
||||
* @see uc_payment_delete_confirm_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_payment_delete_confirm_form($form, &$form_state, $order, $payment) {
|
||||
// Make sure the payment is for the specified order.
|
||||
if ($payment->order_id != $order->order_id) {
|
||||
drupal_set_message(t('An error loading the payment information occurred.'));
|
||||
drupal_goto('admin/store/orders/' . $order->order_id . '/payments');
|
||||
}
|
||||
|
||||
$desc = '<strong>' . t('Payment information:') . '</strong> '
|
||||
. t('@method payment of @amount received on @date.', array('@method' => $payment->method, '@amount' => uc_currency_format($payment->amount), '@date' => format_date($payment->received, 'short')));
|
||||
|
||||
$form['order_id'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $order->order_id
|
||||
);
|
||||
$form['receipt_id'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $payment->receipt_id,
|
||||
);
|
||||
|
||||
return confirm_form($form, t('Are you sure you want to delete this payment?'), 'admin/store/orders/' . $order->order_id . '/payments', $desc, t('Delete'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission handler for uc_payment_delete_confirm_form().
|
||||
*
|
||||
* @see uc_payment_delete_confirm_form()
|
||||
*/
|
||||
function uc_payment_delete_confirm_form_submit($form, &$form_state) {
|
||||
uc_payment_delete($form_state['values']['receipt_id']);
|
||||
|
||||
drupal_set_message(t('Payment deleted.'));
|
||||
|
||||
$form_state['redirect'] = 'admin/store/orders/' . $form_state['values']['order_id'] . '/payments';
|
||||
}
|
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks provided by the Payment module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup hooks
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Takes action when a payment is entered for an order.
|
||||
*
|
||||
* @param $order
|
||||
* The order object.
|
||||
* @param $method
|
||||
* The name of the payment method used.
|
||||
* @param $amount
|
||||
* The value of the payment.
|
||||
* @param $account
|
||||
* The user account that entered the order. When the payment is entered
|
||||
* during checkout, this is probably the order's user. Otherwise, it is
|
||||
* likely a store administrator.
|
||||
* @param $data
|
||||
* Extra data associated with the transaction.
|
||||
* @param $comment
|
||||
* Any comments from the user about the transaction.
|
||||
*/
|
||||
function hook_uc_payment_entered($order, $method, $amount, $account, $data, $comment) {
|
||||
drupal_set_message(t('User @uid entered a @method payment of @amount for order @order_id.',
|
||||
array(
|
||||
'@uid' => $account->uid,
|
||||
'@method' => $method,
|
||||
'@amount' => uc_currency_format($amount),
|
||||
'@order_id' => $order->order_id,
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers credit card payment gateway callbacks.
|
||||
*
|
||||
* Payment gateways handle credit card payments directly, without needing to
|
||||
* redirect off-site.
|
||||
*
|
||||
* @see http://www.ubercart.org/docs/api/hook_uc_payment_gateway
|
||||
* @see hook_uc_payment_gateway_charge()
|
||||
*
|
||||
* @return
|
||||
* Returns an array of payment gateways, keyed by the gateway ID, and with
|
||||
* the following members:
|
||||
* - "title": the human-readable name of the payment method.
|
||||
* - "description": a human-readable description of the payment method.
|
||||
* - "settings": A callback function that returns the gateway settings form.
|
||||
* - "credit": A callback function that processes the credit card. See
|
||||
* hook_uc_payment_gateway_charge() for details.
|
||||
*/
|
||||
function hook_uc_payment_gateway() {
|
||||
$gateways['test_gateway'] = array(
|
||||
'title' => t('Test gateway'),
|
||||
'description' => t('Process credit card payments through the Test Gateway.'),
|
||||
'credit' => 'test_gateway_charge',
|
||||
);
|
||||
return $gateways;
|
||||
}
|
||||
|
||||
/**
|
||||
* Credit card charge callback.
|
||||
*
|
||||
* Called when a credit card should be processed. Credit card details supplied
|
||||
* by the user are available in $order->payment_details[].
|
||||
*
|
||||
* @see hook_uc_payment_gateway()
|
||||
* @see uc_authorizenet_charge()
|
||||
* @see test_gateway_charge()
|
||||
*
|
||||
* @param $order_id
|
||||
* The order ID that the payment relates to.
|
||||
* @param $amount
|
||||
* The amount that should be charged.
|
||||
* @param $data
|
||||
* An array of data related to the charge. By default, includes a 'txn_type'
|
||||
* key which defines the transaction type, usually UC_CREDIT_AUTH_ONLY
|
||||
* or UC_CREDIT_AUTH_CAPTURE.
|
||||
*
|
||||
* @return
|
||||
* Returns an associative array with the following members:
|
||||
* - "success": TRUE if the transaction succeeded, FALSE otherwise.
|
||||
* - "message": a human-readable message describing the result of the
|
||||
* transaction.
|
||||
* - "log_payment": TRUE if the transaction should be regarded as a
|
||||
* successful payment.
|
||||
*/
|
||||
function hook_uc_payment_gateway_charge($order_id, $amount, $data) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Alters payment gateways.
|
||||
*
|
||||
* @param $gateways
|
||||
* Array of payment gateways passed by reference. Array is structured like
|
||||
* the return value of hook_uc_payment_gateway().
|
||||
*/
|
||||
function hook_uc_payment_gateway_alter(&$gateways) {
|
||||
// Change the title of the test gateway.
|
||||
$gateways['test_gateway']['title'] = t('Altered test gateway title.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers callbacks for payment methods.
|
||||
*
|
||||
* Payment methods are different ways to collect payment. By default, Ubercart
|
||||
* comes with support for check, credit card, and generic payments. Payment
|
||||
* methods show up at checkout or on the order administration screens, and they
|
||||
* collect different sorts of information from the user that is used to process
|
||||
* or track the payment.
|
||||
*
|
||||
* @see hook_uc_payment_method_callback()
|
||||
*
|
||||
* @return
|
||||
* An array of payment methods. The array contains a sub-array for each
|
||||
* payment method, with the machine-readable type name as the key. Required
|
||||
* attributes:
|
||||
* - "name": the human-readable name of the payment method.
|
||||
* - "title": the human-readable title of the payment method, displayed
|
||||
* during checkout.
|
||||
* - "desc": a human-readable description of the payment method.
|
||||
* - "callback": a callback function that handles operations that the method
|
||||
* may need to perform. See hook_uc_payment_method_callback()
|
||||
* - "weight": the default weight of the payment method.
|
||||
* - "checkout": if TRUE, the payment method will be enabled by default.
|
||||
* - "no_gateway": should be set to TRUE, except for uc_credit which uses
|
||||
* payment gateways.
|
||||
* - "redirect": if set, this payment method redirects off site; this key
|
||||
* specifies a callback function which will be used to generate the form
|
||||
* that redirects the user to the payment gateway pages.
|
||||
*/
|
||||
function hook_uc_payment_method() {
|
||||
$methods['check'] = array(
|
||||
'name' => t('Check'),
|
||||
'title' => t('Check or money order'),
|
||||
'desc' => t('Pay by mailing a check or money order.'),
|
||||
'callback' => 'uc_payment_method_callback',
|
||||
'weight' => 1,
|
||||
'checkout' => TRUE,
|
||||
);
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to perform various operations for a payment method.
|
||||
*
|
||||
* Possible operations are as follows:
|
||||
* - "cart-details": The payment method has been selected at checkout. Return
|
||||
* a form or render array to be displayed in the payment method pane.
|
||||
* - "cart-process": Called when the user submits the checkout form with this
|
||||
* payment method selected, used to process any form elements output by the
|
||||
* 'cart-details' op. Return FALSE to abort the checkout process, or NULL or
|
||||
* TRUE to continue with checkout.
|
||||
* - "cart-review": Called when the checkout review page is being displayed.
|
||||
* Return an array of data to be displayed below the payment method title on
|
||||
* the checkout review page.
|
||||
* - "customer-view": Called when the order is being displayed to a customer.
|
||||
* Return a render array to be displayed to customers.
|
||||
* - "order-delete": Called when an order is being deleted. Payment methods
|
||||
* should clean up any extra data they stored related to the order.
|
||||
* - "order-details": Called when an order is being edited by an administrator.
|
||||
* Return a string or a form array to be displayed to the administator.
|
||||
* - "order-load": Called from hook_uc_order('load') when this payment method
|
||||
* is selected for the order.
|
||||
* - "order-process": Called when an order has been edited by an administrator.
|
||||
* Process any form elements returned by the "order-details" op.
|
||||
* - "order-save": Called from hook_uc_order('save') when this payment method
|
||||
* is selected for the order.
|
||||
* - "order-submit": Called from hook_uc_order('submit') when this payment
|
||||
* method is selected for the order.
|
||||
* - "order-view": Called when the order is being displayed on the order admin
|
||||
* pages. Return a render array to be displayed to administrators.
|
||||
* - "settings": Called when the payment methods page is being displayed.
|
||||
* Return a system settings form array to configure the payment method.
|
||||
*
|
||||
* @see hook_uc_payment_method()
|
||||
*
|
||||
* @param $op
|
||||
* The operation being performed.
|
||||
* @param &$order
|
||||
* The order object that relates to this operation.
|
||||
* @param $form
|
||||
* Where applicable, the form object that relates to this operation.
|
||||
* @param &$form_state
|
||||
* Where applicable, the form state that relates to this operation.
|
||||
*
|
||||
* @return
|
||||
* Dependent on $op.
|
||||
*/
|
||||
function hook_uc_payment_method_callback($op, &$order, $form = NULL, &$form_state = NULL) {
|
||||
switch ($op) {
|
||||
case 'cart-details':
|
||||
return array('#markup' => t('Continue with checkout to complete payment.'));
|
||||
|
||||
case 'settings':
|
||||
$form['uc_payment_method_account_number'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Payment gateway account number'),
|
||||
'#default_value' => variable_get('uc_payment_method_account_number', ''),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter payment methods.
|
||||
*
|
||||
* @param $methods
|
||||
* Array of payment methods passed by reference. Array is structured like
|
||||
* the return value of hook_uc_payment_method().
|
||||
*/
|
||||
function hook_uc_payment_method_alter(&$methods) {
|
||||
// Change the title of the Check payment method.
|
||||
$methods['check']['title'] = t('Cheque');
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter payment methods available at checkout.
|
||||
*
|
||||
* @param $methods
|
||||
* Array of payment methods passed by reference. Keys are payment method IDs,
|
||||
* strings are payment method titles.
|
||||
* @param $order
|
||||
* The order that is being checked out.
|
||||
*/
|
||||
function hook_uc_payment_method_checkout_alter(&$methods, $order) {
|
||||
// Remove the Check payment method for orders under $100.
|
||||
if ($order->order_total < 100) {
|
||||
unset($methods['check']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "addtogroup hooks".
|
||||
*/
|
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file
|
||||
* Styles for uc_payment module.
|
||||
*/
|
||||
|
||||
.uc-credit-cctype {
|
||||
vertical-align: middle;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
#paypal-includes {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#payment-details {
|
||||
border-top: solid 1px #bbb;
|
||||
clear: both;
|
||||
margin-top: 1em;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.payment-details-cod .form-item {
|
||||
display: block;
|
||||
float: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.payment-details-credit .form-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.payment-details-credit label {
|
||||
clear: left;
|
||||
float: left;
|
||||
margin: 2px 0;
|
||||
padding-top: 5px;
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
.payment-details-credit input,
|
||||
.payment-details-credit select {
|
||||
float: left;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.form-item-panes-payment-details-cc-start-year label,
|
||||
.form-item-panes-payment-details-cc-exp-year label,
|
||||
.form-item-cc-data-cc-start-year label,
|
||||
.form-item-cc-data-cc-exp-year label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.payment-details-credit .field-suffix {
|
||||
float: left;
|
||||
margin: 2px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
img.uc-2checkout-logo {
|
||||
position: relative;
|
||||
left: 2.2em;
|
||||
}
|
||||
|
||||
#line-items-div {
|
||||
border: 1px solid #bbb;
|
||||
float: right;
|
||||
margin: 0 0 1em 1em;
|
||||
}
|
||||
|
||||
#line-items-div table {
|
||||
margin: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#line-items-div td {
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
|
||||
#line-items-div td.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#uc-payment-by-order-form .form-type-item {
|
||||
float: left;
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
#uc-payment-by-order-form table {
|
||||
clear: left;
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
name = Payment
|
||||
description = Enables payments to be taken at checkout.
|
||||
dependencies[] = uc_order
|
||||
dependencies[] = uc_store
|
||||
package = Ubercart - core (optional)
|
||||
core = 7.x
|
||||
|
||||
; Test cases
|
||||
files[] = tests/uc_payment.test
|
||||
|
||||
configure = admin/store/settings/payment
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Entity Metadata hooks
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_entity_property_info().
|
||||
*/
|
||||
function uc_payment_entity_property_info() {
|
||||
return array(
|
||||
'uc_order' => array(
|
||||
'properties' => array(
|
||||
'payment_balance' => array(
|
||||
'type' => 'decimal',
|
||||
'label' => t('Balance'),
|
||||
'description' => t('The total amount remaining for the order.'),
|
||||
'getter callback' => 'uc_payment_balance',
|
||||
'query callback' => 'entity_metadata_table_query',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_entity_property_info_alter().
|
||||
*/
|
||||
function uc_payment_entity_property_info_alter(&$info) {
|
||||
$info['uc_order']['properties']['payment_method']['options list'] = 'uc_payment_method_options_list';
|
||||
}
|
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_payment module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function uc_payment_schema() {
|
||||
$schema = array();
|
||||
|
||||
$schema['uc_payment_receipts'] = array(
|
||||
'description' => 'Stores completed payments.',
|
||||
'fields' => array(
|
||||
'receipt_id' => array(
|
||||
'description' => 'Primary key: the payment receipt ID.',
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'order_id' => array(
|
||||
'description' => 'The {uc_orders}.order_id.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'method' => array(
|
||||
'description' => 'The payment method.',
|
||||
'type' => 'varchar',
|
||||
'length' => 32,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'amount' => array(
|
||||
'description' => 'The payment amount in the store default currency.',
|
||||
'type' => 'numeric',
|
||||
'precision' => 16,
|
||||
'scale' => 5,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'uid' => array(
|
||||
'description' => 'The {users}.uid who collected the payment.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'data' => array(
|
||||
'description' => 'A serialized array of extra payment data.',
|
||||
'type' => 'text',
|
||||
'serialize' => TRUE,
|
||||
),
|
||||
'comment' => array(
|
||||
'description' => 'A comment made on the payment.',
|
||||
'type' => 'text',
|
||||
),
|
||||
'received' => array(
|
||||
'description' => 'The Unix timestamp indicating when the payment was received.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'order_id' => array('order_id'),
|
||||
),
|
||||
'primary key' => array('receipt_id'),
|
||||
'foreign keys' => array(
|
||||
'uc_orders' => array(
|
||||
'table' => 'uc_orders',
|
||||
'columns' => array('order_id' => 'order_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function uc_payment_install() {
|
||||
$t = get_t();
|
||||
|
||||
db_insert('uc_order_statuses')
|
||||
->fields(array(
|
||||
'order_status_id' => 'payment_received',
|
||||
'title' => $t('Payment received'),
|
||||
'state' => 'payment_received',
|
||||
'weight' => 10,
|
||||
'locked' => 1,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_payment_uninstall() {
|
||||
db_delete('variable')
|
||||
->condition(db_or()
|
||||
->condition('name', 'uc_pg_%', 'LIKE')
|
||||
->condition('name', 'uc_payment_%', 'LIKE'))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function uc_payment_update_last_removed() {
|
||||
// 7.x-3.0-beta2 and earlier were installed with schema version 0,
|
||||
// which causes update.php to fail.
|
||||
return drupal_get_installed_schema_version('uc_payment') == 0 ? 0 : 6002;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unused variables.
|
||||
*/
|
||||
function uc_payment_update_7000() {
|
||||
variable_del('uc_payment_tracking');
|
||||
variable_del('uc_payment_deleting');
|
||||
variable_del('uc_payment_logging');
|
||||
variable_del('uc_default_payment_msg');
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase maximum length of comment field.
|
||||
*/
|
||||
function uc_payment_update_7001() {
|
||||
db_change_field('uc_payment_receipts', 'comment', 'comment', array(
|
||||
'description' => 'A comment made on the payment.',
|
||||
'type' => 'text',
|
||||
));
|
||||
}
|
@@ -0,0 +1,700 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines the payment API that lets payment modules interact with Ubercart.
|
||||
*
|
||||
* The payment system in Ubercart relies on hooks to let the main program know
|
||||
* what payment modules are installed and what their current settings are. The
|
||||
* customer can choose a payment type at checkout, and the proper information
|
||||
* will be collected to complete the purchase.
|
||||
*/
|
||||
|
||||
require_once dirname(__FILE__) . '/uc_payment_checkout_pane.inc';
|
||||
require_once dirname(__FILE__) . '/uc_payment_order_pane.inc';
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function uc_payment_menu() {
|
||||
$items['admin/store/settings/payment'] = array(
|
||||
'title' => 'Payment methods',
|
||||
'description' => 'Choose and configure available payment methods.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('uc_payment_methods_form'),
|
||||
'access arguments' => array('administer store'),
|
||||
'file' => 'uc_payment.admin.inc',
|
||||
);
|
||||
$items['admin/store/settings/payment/method/%'] = array(
|
||||
'title callback' => 'uc_payment_method_title',
|
||||
'title arguments' => array(5),
|
||||
'description' => 'Configures a specific payment method.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('uc_payment_method_settings_form', 5),
|
||||
'access arguments' => array('administer store'),
|
||||
'file' => 'uc_payment.admin.inc',
|
||||
);
|
||||
$items += rules_ui()->config_menu('admin/store/settings/payment');
|
||||
|
||||
$items['admin/store/orders/%uc_order/payments'] = array(
|
||||
'title' => 'Payments',
|
||||
'description' => 'Show payments made against an order.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('uc_payment_by_order_form', 3),
|
||||
'access arguments' => array('view payments'),
|
||||
'weight' => 5,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'uc_payment.admin.inc',
|
||||
);
|
||||
$items['admin/store/orders/%uc_order/payments/%uc_payment/delete'] = array(
|
||||
'title' => 'Delete payment?',
|
||||
'description' => 'Delete payment?',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('uc_payment_delete_confirm_form', 3, 5),
|
||||
'access arguments' => array('delete payments'),
|
||||
'type' => MENU_CALLBACK,
|
||||
'file' => 'uc_payment.admin.inc',
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title callback for payment method settings.
|
||||
*/
|
||||
function uc_payment_method_title($method_id) {
|
||||
return t('!method settings', array('!method' => _uc_payment_method_data($method_id, 'name')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function uc_payment_permission() {
|
||||
return array(
|
||||
'view payments' => array(
|
||||
'title' => t('View payments'),
|
||||
),
|
||||
'manual payments' => array(
|
||||
'title' => t('Manual payments'),
|
||||
'description' => t('Enter payments manually.'),
|
||||
),
|
||||
'delete payments' => array(
|
||||
'title' => t('Delete payments'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*/
|
||||
function uc_payment_theme() {
|
||||
return array(
|
||||
'uc_payment_totals' => array(
|
||||
'variables' => array('order' => NULL),
|
||||
'file' => 'uc_payment.theme.inc',
|
||||
),
|
||||
'uc_payment_method_table' => array(
|
||||
'render element' => 'form',
|
||||
'file' => 'uc_payment.admin.inc',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter() for uc_cart_view_form().
|
||||
*
|
||||
* Adds express buttons for enabled payment modules directly to the cart page.
|
||||
*/
|
||||
function uc_payment_form_uc_cart_view_form_alter(&$form, &$form_state) {
|
||||
$methods = _uc_payment_method_list();
|
||||
foreach ($methods as $id => $method) {
|
||||
if ($method['checkout'] && isset($method['express']) && $express = $method['express'](array(), $form_state)) {
|
||||
$form['actions']['checkout'][$id] = $express;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter() for uc_cart_checkout_review_form().
|
||||
*
|
||||
* If a payment method redirects off-site, add the required form to the review
|
||||
* page.
|
||||
*/
|
||||
function uc_payment_form_uc_cart_checkout_review_form_alter(&$form, &$form_state) {
|
||||
$order = $form_state['uc_order'];
|
||||
|
||||
if ($redirect = _uc_payment_method_data($order->payment_method, 'redirect')) {
|
||||
unset($form['actions']['submit']);
|
||||
$suffix = drupal_get_form($redirect, $order);
|
||||
$form['#suffix'] = drupal_render($suffix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_order().
|
||||
*/
|
||||
function uc_payment_uc_order($op, $order) {
|
||||
if (!isset($order->payment_method)) {
|
||||
$order->payment_method = '';
|
||||
}
|
||||
|
||||
switch ($op) {
|
||||
case 'submit':
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func)) {
|
||||
return $func('order-submit', $order);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'load':
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func)) {
|
||||
$func('order-load', $order);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'save':
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func)) {
|
||||
$func('order-save', $order);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'can_delete':
|
||||
if (uc_payment_load_payments($order->order_id) !== FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
db_delete('uc_payment_receipts')
|
||||
->condition('order_id', $order->order_id)
|
||||
->execute();
|
||||
|
||||
// Call each payment method to delete method-specific data from the
|
||||
// database.
|
||||
$methods = _uc_payment_method_list();
|
||||
foreach ($methods as $method) {
|
||||
$func = $method['callback'];
|
||||
if (function_exists($func)) {
|
||||
$func('order-delete', $order);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_checkout_pane().
|
||||
*/
|
||||
function uc_payment_uc_checkout_pane() {
|
||||
$panes['payment'] = array(
|
||||
'title' => t('Payment method'),
|
||||
'desc' => t('Select a payment method from the enabled payment modules.'),
|
||||
'callback' => 'uc_checkout_pane_payment',
|
||||
'weight' => 6,
|
||||
);
|
||||
|
||||
return $panes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_order_pane().
|
||||
*/
|
||||
function uc_payment_uc_order_pane() {
|
||||
$panes['payment'] = array(
|
||||
'callback' => 'uc_order_pane_payment',
|
||||
'title' => t('Payment'),
|
||||
'desc' => t('Specify and collect payment for an order.'),
|
||||
'class' => 'pos-left',
|
||||
'weight' => 4,
|
||||
'show' => array('view', 'edit', 'customer'),
|
||||
);
|
||||
|
||||
return $panes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_order_state().
|
||||
*/
|
||||
function uc_payment_uc_order_state() {
|
||||
$states['payment_received'] = array(
|
||||
'title' => t('Payment received'),
|
||||
'weight' => 10,
|
||||
'scope' => 'general',
|
||||
);
|
||||
|
||||
return $states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_payment_method().
|
||||
*/
|
||||
function uc_payment_uc_payment_method() {
|
||||
$methods['free_order'] = array(
|
||||
'name' => t('Free order'),
|
||||
'title' => t('No payment required'),
|
||||
'desc' => t('Allow customers with !zero order totals to checkout without paying.', array('!zero' => uc_currency_format(0))),
|
||||
'callback' => 'uc_payment_method_free_order',
|
||||
'checkout' => TRUE,
|
||||
'no_gateway' => TRUE,
|
||||
'weight' => 0,
|
||||
);
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_payment_method_checkout_alter().
|
||||
*/
|
||||
function uc_payment_uc_payment_method_checkout_alter(&$methods, $order) {
|
||||
if (isset($methods['free_order'])) {
|
||||
if ($order->order_total < 0.01) {
|
||||
// Unset all other payment methods if this is a free order.
|
||||
foreach (array_keys($methods) as $key) {
|
||||
if ($key != 'free_order') {
|
||||
unset($methods[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Disallow this payment method if the order is not free.
|
||||
unset($methods['free_order']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment method callback for free orders.
|
||||
*
|
||||
* @see uc_payment_uc_payment_method()
|
||||
*/
|
||||
function uc_payment_method_free_order($op, &$order) {
|
||||
switch ($op) {
|
||||
case 'cart-details':
|
||||
return array(
|
||||
'#markup' => t('Continue with checkout to complete your order.'),
|
||||
);
|
||||
|
||||
case 'order-submit':
|
||||
if ($order->order_total >= 0.01) {
|
||||
return array(array(
|
||||
'pass' => FALSE,
|
||||
'message' => t('We cannot process your order without payment.'),
|
||||
));
|
||||
}
|
||||
|
||||
uc_payment_enter($order->order_id, 'free_order', 0, 0, NULL, t('Checkout completed for a free order.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted list of line items for an order total preview.
|
||||
*
|
||||
* @param $return
|
||||
* TRUE or FALSE to specify whether or not to return the results instead of
|
||||
* printing them and exiting.
|
||||
* @param $order
|
||||
* Optionally pass in a full order object to use instead of finding it in the
|
||||
* $_POST data.
|
||||
*
|
||||
* @return
|
||||
* The formatted HTML of the order total preview if $return is set to TRUE.
|
||||
*/
|
||||
function uc_payment_get_totals($form, $form_state) {
|
||||
$commands[] = ajax_command_replace('#line-items-div', trim(drupal_render($form['panes']['payment']['line_items'])));
|
||||
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* TAPIr table definition for uc_payments_table.
|
||||
*/
|
||||
function uc_payments_table() {
|
||||
$table = array(
|
||||
'#type' => 'tapir_table',
|
||||
'#tree' => TRUE,
|
||||
'#columns' => array(
|
||||
'received' => array(
|
||||
'cell' => t('Received'),
|
||||
'weight' => 0,
|
||||
),
|
||||
'user' => array(
|
||||
'cell' => t('User'),
|
||||
'weight' => 1,
|
||||
),
|
||||
'method' => array(
|
||||
'cell' => t('Method'),
|
||||
'weight' => 2,
|
||||
),
|
||||
'amount' => array(
|
||||
'cell' => t('Amount'),
|
||||
'weight' => 3,
|
||||
),
|
||||
'balance' => array(
|
||||
'cell' => t('Balance'),
|
||||
'weight' => 4,
|
||||
),
|
||||
'comment' => array(
|
||||
'cell' => t('Comment'),
|
||||
'weight' => 5,
|
||||
),
|
||||
'action' => array(
|
||||
'cell' => t('Action'),
|
||||
'weight' => 6,
|
||||
),
|
||||
),
|
||||
'#rows' => array(),
|
||||
);
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a payment through an enabled payment gateway.
|
||||
*
|
||||
* @param $method
|
||||
* The ID of the payment method to use to process the payment.
|
||||
* @param $order_id
|
||||
* The ID of the order associated with this payment.
|
||||
* @param $amount
|
||||
* The amount of the payment we're attempting to collect.
|
||||
* @param $data
|
||||
* An array of data passed on to the payment gateway module used to process
|
||||
* the payment for the specified payment method.
|
||||
* @param $default
|
||||
* TRUE or FALSE to indicate we're forcing the use of the default gateway for
|
||||
* the specified payment method. When TRUE, admin messages related to the
|
||||
* payment will be hidden from display so customers don't see them.
|
||||
* @param $selected
|
||||
* The ID of a payment gateway to use to process the payment; normally comes
|
||||
* from the payment gateway select form.
|
||||
* @param $redirect
|
||||
* TRUE or FALSE to indicate whether or not to redirect back to the admin
|
||||
* order view page for the order referenced in $order_id.
|
||||
*
|
||||
* @return
|
||||
* TRUE or FALSE indicating whether or not the payment was processed.
|
||||
*/
|
||||
function uc_payment_process_payment($method, $order_id, $amount, $data = NULL, $default = FALSE, $selected = NULL, $redirect = TRUE) {
|
||||
$result = array();
|
||||
|
||||
// Get an array of enabled payment gateways available for the payment method.
|
||||
$gateways = _uc_payment_gateway_list($method, TRUE);
|
||||
|
||||
// Fail if no gateways were found for the specified method.
|
||||
if (empty($gateways)) {
|
||||
// Display an error message if messages weren't silenced.
|
||||
if (!$default) {
|
||||
drupal_set_message(t('You are not able to process %type payments.', array('%type' => _uc_payment_method_data($method, 'name'))));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Find the default gateway if requested.
|
||||
if ($default) {
|
||||
$default = variable_get('uc_payment_' . $method . '_gateway', '');
|
||||
}
|
||||
|
||||
// If we only found one gateway for this payment method...
|
||||
if (count($gateways) == 1) {
|
||||
$gateway = reset($gateways);
|
||||
}
|
||||
elseif ($default && isset($gateways[$default])) {
|
||||
// The default gateway was forced.
|
||||
$gateway = $gateways[$default];
|
||||
}
|
||||
elseif ($selected && isset($gateways[$selected])) {
|
||||
// A specific gateway was selected.
|
||||
$gateway = $gateways[$selected];
|
||||
}
|
||||
else {
|
||||
// No gateway available.
|
||||
$gateway = array($method => '');
|
||||
}
|
||||
|
||||
// Check to see if the function exists and process the payment.
|
||||
if (function_exists($gateway[$method])) {
|
||||
// Reset the entity cache, so the latest data saved in the credit card cache
|
||||
// is guaranteed to be available in the charge function.
|
||||
uc_order_load($order_id, TRUE);
|
||||
|
||||
$result = $gateway[$method]($order_id, $amount, $data);
|
||||
}
|
||||
else {
|
||||
// Otherwise display an error message to administrators.
|
||||
$result['success'] = FALSE;
|
||||
$result['message'] = t('An error has occurred with your payment gateway. The charge function could not be found.');
|
||||
if (user_access('administer store')) {
|
||||
drupal_set_message($result['message']);
|
||||
}
|
||||
}
|
||||
|
||||
// If the payment processed successfully...
|
||||
if ($result['success'] === TRUE) {
|
||||
// Log the payment to the order if not disabled.
|
||||
if (!isset($result['log_payment']) || $result['log_payment'] !== FALSE) {
|
||||
uc_payment_enter($order_id, $method, $amount, empty($result['uid']) ? 0 : $result['uid'], empty($result['data']) ? '' : $result['data'], empty($result['comment']) ? '' : $result['comment']);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Otherwise display the failure message in the logs.
|
||||
watchdog('uc_payment', 'Payment failed for order @order_id: @message', array('@order_id' => $order_id, '@message' => $result['message']), WATCHDOG_WARNING, l(t('view order'), 'admin/store/orders/' . $order_id));
|
||||
}
|
||||
|
||||
// If we have a message for display and aren't simply charging with the
|
||||
// default gateway for a customer...
|
||||
if (!empty($result['message']) && !$default) {
|
||||
drupal_set_message($result['message']);
|
||||
}
|
||||
|
||||
// Head back to the order if a redirect was specified.
|
||||
if ($redirect) {
|
||||
drupal_goto('admin/store/orders/' . $order_id);
|
||||
}
|
||||
|
||||
return $result['success'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters a payment for an order.
|
||||
*
|
||||
* @param $order_id
|
||||
* The order ID to apply the payment to.
|
||||
* @param $method
|
||||
* The payment method ID.
|
||||
* @param $amount
|
||||
* The amount of the payment.
|
||||
* @param $uid
|
||||
* (optional) The user ID of the person logging the payment, or 0 if the
|
||||
* payment was processed automatically.
|
||||
* @param $data
|
||||
* (optional) Any data that should be serialized and stored with the
|
||||
* payment.
|
||||
* @param $comment
|
||||
* (optional) The comment to enter in the payment log.
|
||||
* @param $received
|
||||
* (optional) The timestamp at which the payment was received.
|
||||
*
|
||||
* @return
|
||||
* A unique ID identifying the payment.
|
||||
*/
|
||||
function uc_payment_enter($order_id, $method, $amount, $uid = 0, $data = NULL, $comment = '', $received = REQUEST_TIME) {
|
||||
$method_name = _uc_payment_method_data($method, 'review');
|
||||
if (empty($method_name)) {
|
||||
$method_name = _uc_payment_method_data($method, 'name');
|
||||
}
|
||||
if (is_null($method_name)) {
|
||||
$method_name = t('Other');
|
||||
}
|
||||
if (is_array($data)) {
|
||||
$data = serialize($data);
|
||||
}
|
||||
|
||||
$log_message = t('@method payment for @amount entered.', array('@method' => $method_name, '@amount' => uc_currency_format($amount)));
|
||||
uc_order_log_changes($order_id, array($log_message));
|
||||
|
||||
$receipt_id = db_insert('uc_payment_receipts')
|
||||
->fields(array(
|
||||
'order_id' => $order_id,
|
||||
'method' => $method_name,
|
||||
'amount' => $amount,
|
||||
'uid' => $uid,
|
||||
'data' => $data,
|
||||
'comment' => $comment,
|
||||
'received' => $received,
|
||||
))
|
||||
->execute();
|
||||
|
||||
$order = uc_order_load($order_id, TRUE);
|
||||
$account = user_load($uid);
|
||||
|
||||
// Ensure user has an account before payment is made.
|
||||
if (module_exists('uc_cart')) {
|
||||
uc_cart_complete_sale($order);
|
||||
}
|
||||
|
||||
module_invoke_all('uc_payment_entered', $order, $method, $amount, $account, $data, $comment);
|
||||
rules_invoke_event('uc_payment_entered', $order, $account);
|
||||
|
||||
return $receipt_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a payment from the database.
|
||||
*/
|
||||
function uc_payment_delete($receipt_id) {
|
||||
if (!is_numeric($receipt_id)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$payment = uc_payment_load($receipt_id);
|
||||
$log_message = t('@method payment for @amount deleted.', array('@method' => $payment->method, '@amount' => uc_currency_format($payment->amount)));
|
||||
uc_order_log_changes($payment->order_id, array($log_message));
|
||||
|
||||
db_delete('uc_payment_receipts')
|
||||
->condition('receipt_id', $receipt_id)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the balance of payments on an order.
|
||||
*/
|
||||
function uc_payment_balance($order) {
|
||||
$total = $order->order_total;
|
||||
$payments = uc_payment_load_payments($order->order_id);
|
||||
|
||||
if ($payments === FALSE) {
|
||||
return $total;
|
||||
}
|
||||
|
||||
foreach ($payments as $payment) {
|
||||
$total -= $payment->amount;
|
||||
}
|
||||
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a single payment from the database by receipt_id.
|
||||
*/
|
||||
function uc_payment_load($receipt_id) {
|
||||
if (!is_numeric($receipt_id)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$payment = db_query("SELECT * FROM {uc_payment_receipts} WHERE receipt_id = :id", array(':id' => $receipt_id))->fetchObject();
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an array of all the payments for an order.
|
||||
*
|
||||
* @param $order_id
|
||||
* The order's id.
|
||||
*
|
||||
* @return
|
||||
* Array of payment objects or FALSE if there are none.
|
||||
*/
|
||||
function uc_payment_load_payments($order_id) {
|
||||
$payments = db_query("SELECT * FROM {uc_payment_receipts} WHERE order_id = :id ORDER BY received ASC", array(':id' => $order_id))->fetchAll();
|
||||
|
||||
if (count($payments) == 0) {
|
||||
$payments = FALSE;
|
||||
}
|
||||
|
||||
return $payments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a list of payment methods defined in the enabled modules.
|
||||
*/
|
||||
function _uc_payment_method_list($action = NULL) {
|
||||
static $methods = array();
|
||||
|
||||
if (count($methods) > 0 && $action !== 'rebuild') {
|
||||
return $methods;
|
||||
}
|
||||
|
||||
foreach (module_invoke_all('uc_payment_method') as $id => $method) {
|
||||
// Preserve backward compatibility for methods with no key specified.
|
||||
if (is_numeric($id)) {
|
||||
$id = $method['id'];
|
||||
}
|
||||
|
||||
$methods[$id] = array_merge($method, array(
|
||||
'id' => $id,
|
||||
'checkout' => variable_get('uc_payment_method_' . $id . '_checkout', $method['checkout']),
|
||||
'weight' => variable_get('uc_payment_method_' . $id . '_weight', $method['weight']),
|
||||
));
|
||||
}
|
||||
|
||||
// Allow other modules to alter the payment methods.
|
||||
drupal_alter('uc_payment_method', $methods);
|
||||
|
||||
uasort($methods, 'uc_weight_sort');
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data from a payment method by method ID and the array key.
|
||||
*/
|
||||
function _uc_payment_method_data($method_id, $key) {
|
||||
$methods = _uc_payment_method_list();
|
||||
return isset($methods[$method_id][$key]) ? $methods[$method_id][$key] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a list of payment gateways defined in the enabled modules.
|
||||
*/
|
||||
function _uc_payment_gateway_list($filter = NULL, $enabled_only = FALSE) {
|
||||
$gateways = array();
|
||||
|
||||
foreach (module_invoke_all('uc_payment_gateway') as $id => $gateway) {
|
||||
// Preserve backward compatibility for gateways with no key specified.
|
||||
if (is_numeric($id)) {
|
||||
$id = $gateway['id'];
|
||||
}
|
||||
|
||||
$gateways[$id] = array_merge($gateway, array(
|
||||
'id' => $id,
|
||||
'enabled' => variable_get('uc_pg_' . $id . '_enabled', TRUE),
|
||||
));
|
||||
}
|
||||
|
||||
// Allow other modules to alter the payment gateways.
|
||||
drupal_alter('uc_payment_gateway', $gateways);
|
||||
|
||||
foreach ($gateways as $id => $gateway) {
|
||||
if ($filter && (!isset($gateway[$filter]) || !function_exists($gateway[$filter]))) {
|
||||
unset($gateways[$id]);
|
||||
continue;
|
||||
}
|
||||
if ($enabled_only && !$gateway['enabled']) {
|
||||
unset($gateways[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
return $gateways;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns data from a payment gateway by gateway ID and the array key.
|
||||
*
|
||||
* @param $gateway_id
|
||||
* The ID of the payment gateway to query.
|
||||
* @param $key
|
||||
* The key of the data being requested.
|
||||
*
|
||||
* @return
|
||||
* The requested data.
|
||||
*/
|
||||
function _uc_payment_gateway_data($gateway_id, $key) {
|
||||
$gateways = _uc_payment_gateway_list();
|
||||
return isset($gateways[$gateway_id][$key]) ? $gateways[$gateway_id][$key] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an option list of payment methods.
|
||||
*/
|
||||
function uc_payment_method_options_list() {
|
||||
$options = array();
|
||||
foreach (_uc_payment_method_list() as $id => $method) {
|
||||
$options[$id] = $method['name'];
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_views_api().
|
||||
*/
|
||||
function uc_payment_views_api() {
|
||||
return array(
|
||||
'api' => '2.0',
|
||||
'path' => drupal_get_path('module', 'uc_payment') . '/views',
|
||||
);
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Rules definitions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_rules_event_info().
|
||||
*/
|
||||
function uc_payment_rules_event_info() {
|
||||
$events['uc_payment_entered'] = array(
|
||||
'label' => t('A payment gets entered for an order'),
|
||||
'group' => t('Payment'),
|
||||
'variables' => array(
|
||||
'order' => array(
|
||||
'type' => 'uc_order',
|
||||
'label' => t('Order'),
|
||||
),
|
||||
'account' => array(
|
||||
'type' => 'user',
|
||||
'label' => t('User'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_rules_condition_info().
|
||||
*/
|
||||
function uc_payment_rules_condition_info() {
|
||||
$conditions['uc_payment_condition_order_balance'] = array(
|
||||
'label' => t('Check the order balance'),
|
||||
'group' => t('Payment'),
|
||||
'base' => 'uc_payment_condition_order_balance',
|
||||
'parameter' => array(
|
||||
'order' => array(
|
||||
'type' => 'uc_order',
|
||||
'label' => t('Order'),
|
||||
'restriction' => 'selector',
|
||||
),
|
||||
'balance_comparison' => array(
|
||||
'type' => 'text',
|
||||
'label' => t('Operator'),
|
||||
'options list' => 'uc_payment_condition_balance_options',
|
||||
'restriction' => 'input',
|
||||
),
|
||||
'include_authorizations' => array(
|
||||
'type' => 'boolean',
|
||||
'label' => t('Include authorizations?'),
|
||||
'description' => t('Should "authorization only" credit card transactions be used in calculating the order balance?'),
|
||||
'restriction' => 'input',
|
||||
'optional' => TRUE,
|
||||
'default value' => FALSE,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Condition: Check the current order balance.
|
||||
*/
|
||||
function uc_payment_condition_order_balance($order, $balance_comparison, $include_authorizations) {
|
||||
$balance = uc_payment_balance($order);
|
||||
if ($include_authorizations) {
|
||||
foreach ((array) $order->data['cc_txns']['authorizations'] as $auth_id => $data) {
|
||||
$balance -= $data['amount'];
|
||||
}
|
||||
}
|
||||
|
||||
switch ($balance_comparison) {
|
||||
case 'less':
|
||||
return $balance < 0;
|
||||
case 'less_equal':
|
||||
return $balance <= 0.01;
|
||||
case 'equal':
|
||||
return $balance < 0.01 && $balance > -0.01;
|
||||
case 'greater':
|
||||
return $balance >= 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns balance options.
|
||||
*/
|
||||
function uc_payment_condition_balance_options() {
|
||||
$zero = array('!zero' => uc_currency_format(0));
|
||||
$options = array(
|
||||
'less' => t('Balance is less than !zero.', $zero),
|
||||
'less_equal' => t('Balance is less than or equal to !zero.', $zero),
|
||||
'equal' => t('Balance is equal to !zero.', $zero),
|
||||
'greater' => t('Balance is greater than !zero.', $zero),
|
||||
);
|
||||
|
||||
return $options;
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Default rules configurations.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_default_rules_configuration().
|
||||
*/
|
||||
function uc_payment_default_rules_configuration() {
|
||||
$configs = array();
|
||||
|
||||
// Set the order status to "Payment Received" when a payment is received
|
||||
// and the balance is less than or equal to 0.
|
||||
$rule = rules_reaction_rule();
|
||||
$rule->label = t('Update order status on full payment');
|
||||
$rule->active = TRUE;
|
||||
$rule->event('uc_payment_entered')
|
||||
->condition('uc_payment_condition_order_balance', array(
|
||||
'order:select' => 'order',
|
||||
'balance_comparison' => 'less_equal',
|
||||
))
|
||||
->condition(rules_or()
|
||||
->condition('uc_order_condition_order_state', array(
|
||||
'order:select' => 'order',
|
||||
'order_state' => 'in_checkout',
|
||||
))
|
||||
->condition('uc_order_condition_order_state', array(
|
||||
'order:select' => 'order',
|
||||
'order_state' => 'post_checkout',
|
||||
))
|
||||
)
|
||||
->action('uc_order_update_status', array(
|
||||
'order:select' => 'order',
|
||||
'order_status' => 'payment_received',
|
||||
));
|
||||
$configs['uc_payment_received'] = $rule;
|
||||
|
||||
// Set the order status to "Completed" when checkout is complete, none
|
||||
// of the products are shippable, and the balance is less than or equal to 0.
|
||||
$rule = rules_reaction_rule();
|
||||
$rule->label = t('Complete non-shippable order after payment received');
|
||||
$rule->active = TRUE;
|
||||
$rule->event('uc_order_status_update')
|
||||
->condition('data_is', array('data:select' => 'updated_order:order-status', 'value' => 'payment_received'))
|
||||
->condition(rules_condition('uc_order_condition_is_shippable', array(
|
||||
'order:select' => 'updated_order',
|
||||
))
|
||||
->negate())
|
||||
->action('uc_order_update_status', array(
|
||||
'order:select' => 'order',
|
||||
'order_status' => 'completed',
|
||||
));
|
||||
$configs['uc_checkout_complete_paid'] = $rule;
|
||||
|
||||
$methods = _uc_payment_method_list();
|
||||
foreach ($methods as $id => $method) {
|
||||
$set = rules_and(array(
|
||||
'order' => array('type' => 'uc_order', 'label' => t('Order')),
|
||||
));
|
||||
$set->label = t('@method conditions', array('@method' => $method['name']));
|
||||
|
||||
$configs['uc_payment_method_' . $method['id']] = $set;
|
||||
}
|
||||
|
||||
return $configs;
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Theme functions for the uc_payment module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates markup for payment totals.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_uc_payment_totals($variables) {
|
||||
$order = $variables['order'];
|
||||
$line_items = uc_order_load_line_items_display($order);
|
||||
|
||||
$output = '<table id="uc-order-total-preview">';
|
||||
|
||||
foreach ($line_items as $line) {
|
||||
if (!empty($line['title'])) {
|
||||
$attributes = drupal_attributes(array('class' => array('line-item-' . $line['type'])));
|
||||
$output .= '<tr' . $attributes . '><td class="title">' . filter_xss($line['title']) . ':</td>'
|
||||
. '<td class="price">' . theme('uc_price', array('price' => $line['amount'])) . '</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
$output .= '</table>';
|
||||
|
||||
return $output;
|
||||
}
|
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Token hooks for the uc_payment module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_token_info().
|
||||
*/
|
||||
function uc_payment_token_info() {
|
||||
$order['payment-method'] = array(
|
||||
'name' => t('Payment method'),
|
||||
'description' => t('The payment method of the order.'),
|
||||
);
|
||||
$order['payment-balance'] = array(
|
||||
'name' => t('Balance'),
|
||||
'description' => t('The payment balance of the order'),
|
||||
);
|
||||
|
||||
return array(
|
||||
'tokens' => array('uc_order' => $order),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_tokens().
|
||||
*/
|
||||
function uc_payment_tokens($type, $tokens, $data = array(), $options = array()) {
|
||||
$values = array();
|
||||
|
||||
if ($type == 'uc_order' && !empty($data['uc_order'])) {
|
||||
$order = $data['uc_order'];
|
||||
|
||||
if (isset($tokens['payment-method'])) {
|
||||
$original = $tokens['payment-method'];
|
||||
$values[$original] = _uc_payment_method_data($order->payment_method, 'review');
|
||||
if (empty($values[$original])) {
|
||||
$values[$original] = _uc_payment_method_data($order->payment_method, 'name');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($tokens['payment-balance'])) {
|
||||
$original = $tokens['payment-balance'];
|
||||
$values[$original] = uc_currency_format(uc_payment_balance($order));
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Checkout pane functions for uc_payment.module.
|
||||
*
|
||||
* The checkout pane holds form to select the payment method. It also shows a
|
||||
* preview of the line items and order total.
|
||||
*/
|
||||
|
||||
function uc_checkout_pane_payment($op, &$order, $form = NULL, &$form_state = NULL) {
|
||||
switch ($op) {
|
||||
case 'view':
|
||||
$contents['#attached']['css'][] = drupal_get_path('module', 'uc_payment') . '/uc_payment.css';
|
||||
|
||||
if (variable_get('uc_payment_show_order_total_preview', TRUE)) {
|
||||
$contents['line_items'] = array(
|
||||
'#theme' => 'uc_payment_totals',
|
||||
'#order' => $order,
|
||||
'#prefix' => '<div id="line-items-div">',
|
||||
'#suffix' => '</div>',
|
||||
'#weight' => -20,
|
||||
);
|
||||
}
|
||||
|
||||
// Ensure that the form builder uses #default_value to determine which
|
||||
// button should be selected after an ajax submission. This is
|
||||
// necessary because the previously selected value may have become
|
||||
// unavailable, which would result in an invalid selection.
|
||||
unset($form_state['input']['panes']['payment']['payment_method']);
|
||||
|
||||
$options = array();
|
||||
foreach (_uc_payment_method_list() as $id => $method) {
|
||||
$set = rules_config_load('uc_payment_method_' . $method['id']);
|
||||
if ($set && !$set->execute($order)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($method['checkout'] && !isset($method['express'])) {
|
||||
$options[$id] = $method['title'];
|
||||
}
|
||||
}
|
||||
|
||||
drupal_alter('uc_payment_method_checkout', $options, $order);
|
||||
|
||||
$description = '';
|
||||
if (!$options) {
|
||||
$description = t('Checkout cannot be completed without any payment methods enabled. Please contact an administrator to resolve the issue.');
|
||||
$options[''] = t('No payment methods available');
|
||||
}
|
||||
elseif (count($options) > 1) {
|
||||
$description = t('Select a payment method from the following options.');
|
||||
}
|
||||
|
||||
if (!isset($options[$order->payment_method])) {
|
||||
$order->payment_method = key($options);
|
||||
}
|
||||
|
||||
$contents['payment_method'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Payment method'),
|
||||
'#title_display' => 'invisible',
|
||||
'#options' => $options,
|
||||
'#default_value' => $order->payment_method,
|
||||
'#disabled' => count($options) == 1,
|
||||
'#required' => TRUE,
|
||||
'#ajax' => array(
|
||||
'callback' => 'uc_payment_checkout_payment_details',
|
||||
'wrapper' => 'payment-details',
|
||||
'progress' => array(
|
||||
'type' => 'throbber',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$contents['details'] = array(
|
||||
'#prefix' => '<div id="payment-details" class="clearfix payment-details-' . $order->payment_method . '">',
|
||||
'#markup' => t('Continue with checkout to complete payment.'),
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func) && $details = $func('cart-details', $order, $form, $form_state)) {
|
||||
unset($contents['details']['#markup']);
|
||||
$contents['details'] += $details;
|
||||
}
|
||||
|
||||
return array('description' => $description, 'contents' => $contents);
|
||||
|
||||
case 'process':
|
||||
if (empty($form_state['values']['panes']['payment']['payment_method'])) {
|
||||
form_set_error('panes][payment][payment_method', t('You cannot check out without selecting a payment method.'));
|
||||
return FALSE;
|
||||
}
|
||||
$order->payment_method = $form_state['values']['panes']['payment']['payment_method'];
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func)) {
|
||||
$result = $func('cart-process', $order, $form, $form_state);
|
||||
if ($result === FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 'review':
|
||||
$line_items = uc_order_load_line_items_display($order);
|
||||
foreach ($line_items as $line_item) {
|
||||
$review[] = array('title' => $line_item['title'], 'data' => theme('uc_price', array('price' => $line_item['amount'])));
|
||||
}
|
||||
$review_data = _uc_payment_method_data($order->payment_method, 'review');
|
||||
if (empty($review_data)) {
|
||||
$review_data = _uc_payment_method_data($order->payment_method, 'name');
|
||||
}
|
||||
$review[] = array('border' => 'top', 'title' => t('Paying by'), 'data' => $review_data);
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func)) {
|
||||
$result = $func('cart-review', $order);
|
||||
if (is_array($result)) {
|
||||
$review = array_merge($review, $result);
|
||||
}
|
||||
}
|
||||
return $review;
|
||||
|
||||
case 'settings':
|
||||
$form['uc_payment_show_order_total_preview'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Show the order total preview on the payment pane.'),
|
||||
'#default_value' => variable_get('uc_payment_show_order_total_preview', TRUE),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback for payment method details on the checkout form.
|
||||
*/
|
||||
function uc_payment_checkout_payment_details($form, $form_state) {
|
||||
return $form['panes']['payment']['details'];
|
||||
}
|
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains the callbacks for the payment order pane supplied with
|
||||
* Ubercart and their corresponding helper functions.
|
||||
*
|
||||
* Order panes are defined using hook_uc_order_pane() and use a callback to
|
||||
* handle the different processes involved in order viewing/editing. The
|
||||
* payment order pane is defined in uc_payment_uc_order_pane() in
|
||||
* uc_payment.module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles the Payment order pane.
|
||||
*/
|
||||
function uc_order_pane_payment($op, $order, &$form = NULL, &$form_state = NULL) {
|
||||
switch ($op) {
|
||||
case 'view':
|
||||
$build['balance'] = array('#markup' => t('Balance: @balance', array('@balance' => uc_currency_format(uc_payment_balance($order)))));
|
||||
|
||||
if (user_access('view payments')) {
|
||||
$build['view_payments'] = array(
|
||||
'#markup' => ' (' . l(t('View'), 'admin/store/orders/' . $order->order_id . '/payments') . ')',
|
||||
);
|
||||
}
|
||||
|
||||
$method_name = _uc_payment_method_data($order->payment_method, 'review');
|
||||
if (empty($method_name)) {
|
||||
$method_name = _uc_payment_method_data($order->payment_method, 'name');
|
||||
}
|
||||
$build['method'] = array(
|
||||
'#markup' => t('Method: @payment_method', array('@payment_method' => $method_name)),
|
||||
'#prefix' => '<br />',
|
||||
);
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func)) {
|
||||
$method_output = $func('order-view', $order);
|
||||
if (!empty($method_output)) {
|
||||
$build['output'] = $method_output + array(
|
||||
'#prefix' => '<br />',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $build;
|
||||
|
||||
case 'customer':
|
||||
$method_name = _uc_payment_method_data($order->payment_method, 'review');
|
||||
if (empty($method_name)) {
|
||||
$method_name = _uc_payment_method_data($order->payment_method, 'name');
|
||||
}
|
||||
$build['method'] = array('#markup' => t('Method: @payment_method', array('@payment_method' => $method_name)));
|
||||
$func = _uc_payment_method_data($order->payment_method, 'callback');
|
||||
if (function_exists($func)) {
|
||||
$method_output = $func('customer-view', $order);
|
||||
if (!empty($method_output)) {
|
||||
$build['output'] = $method_output + array(
|
||||
'#prefix' => '<br />',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $build;
|
||||
|
||||
case 'edit-form':
|
||||
$methods = _uc_payment_method_list();
|
||||
$options = array();
|
||||
foreach ($methods as $id => $method) {
|
||||
$options[$id] = $method['name'];
|
||||
}
|
||||
$form['payment']['payment_method'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Payment method'),
|
||||
'#default_value' => $order->payment_method,
|
||||
'#options' => !empty($options) ? $options : array(t('None available')),
|
||||
'#disabled' => empty($options),
|
||||
'#ajax' => array(
|
||||
'callback' => 'uc_payment_order_pane_ajax_callback',
|
||||
'progress' => array('type' => 'throbber'),
|
||||
'wrapper' => 'payment-details',
|
||||
),
|
||||
);
|
||||
|
||||
$form['payment']['payment_details'] = array(
|
||||
'#tree' => TRUE,
|
||||
'#prefix' => '<div id="payment-details">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
$method = isset($form_state['values']['payment_method']) ? $form_state['values']['payment_method'] : $order->payment_method;
|
||||
$func = _uc_payment_method_data($method, 'callback');
|
||||
if (function_exists($func) && $details = $func('order-details', $order)) {
|
||||
if (is_array($details)) {
|
||||
$form['payment']['payment_details'] += $details;
|
||||
}
|
||||
else {
|
||||
$form['payment']['payment_details']['#markup'] = $details;
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
|
||||
case 'edit-theme':
|
||||
return drupal_render($form['payment']);
|
||||
|
||||
case 'edit-process':
|
||||
$changes['payment_method'] = $form_state['values']['payment_method'];
|
||||
$changes['payment_details'] = isset($form_state['values']['payment_details']) ? $form_state['values']['payment_details'] : array();
|
||||
$func = _uc_payment_method_data($form_state['values']['payment_method'], 'callback');
|
||||
if (function_exists($func) && ($return = $func('edit-process', $order, $form, $form_state)) != NULL && is_array($return)) {
|
||||
$changes['payment_details'] = array_merge($changes['payment_details'], $return);
|
||||
}
|
||||
|
||||
if (!isset($order->payment_details)) {
|
||||
$order->payment_details = array();
|
||||
}
|
||||
return $changes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback to render the payment method pane.
|
||||
*/
|
||||
function uc_payment_order_pane_ajax_callback($form, &$form_state) {
|
||||
$commands[] = ajax_command_replace('#payment-details', trim(drupal_render($form['payment']['payment_details'])));
|
||||
$commands[] = ajax_command_prepend('#payment-details', theme('status_messages'));
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Views hooks and callback registries.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_views_data().
|
||||
*/
|
||||
function uc_payment_views_data() {
|
||||
$data['uc_orders']['payments'] = array(
|
||||
'relationship' => array(
|
||||
'title' => t('Payments'),
|
||||
'help' => t('Relate payments to an order. This relationship will create one record for each payment received.'),
|
||||
'handler' => 'views_handler_relationship',
|
||||
'base' => 'uc_payment_receipts',
|
||||
'base field' => 'order_id',
|
||||
'relationship field' => 'order_id',
|
||||
'label' => t('payments'),
|
||||
),
|
||||
);
|
||||
|
||||
$data['uc_payment_receipts']['table']['group'] = t('Payment');
|
||||
|
||||
$data['uc_payment_receipts']['method'] = array(
|
||||
'title' => t('Payment method'),
|
||||
'help' => t('The method of payment.'),
|
||||
'field' => array(
|
||||
'handler' => 'views_handler_field',
|
||||
'click sortable' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'handler' => 'views_handler_sort',
|
||||
),
|
||||
'filter' => array(
|
||||
'handler' => 'views_handler_filter_string',
|
||||
),
|
||||
);
|
||||
|
||||
$data['uc_payment_receipts']['amount'] = array(
|
||||
'title' => t('Amount'),
|
||||
'help' => t('The amount paid.'),
|
||||
'field' => array(
|
||||
'handler' => 'uc_order_handler_field_money_amount',
|
||||
'click sortable' => TRUE,
|
||||
'float' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'handler' => 'views_handler_sort',
|
||||
),
|
||||
'filter' => array(
|
||||
'handler' => 'views_handler_filter_numeric',
|
||||
),
|
||||
);
|
||||
|
||||
$data['uc_payment_receipts']['uid'] = array(
|
||||
'title' => t('User'),
|
||||
'help' => t('Relate a payment to the user who made it.'),
|
||||
'relationship' => array(
|
||||
'base' => 'users',
|
||||
'field' => 'uid',
|
||||
'handler' => 'views_handler_relationship',
|
||||
'label' => t('user'),
|
||||
),
|
||||
);
|
||||
|
||||
$data['uc_payment_receipts']['comment'] = array(
|
||||
'title' => t('Comment'),
|
||||
'help' => t('Any remarks that were included with the payment.'),
|
||||
'field' => array(
|
||||
'handler' => 'views_handler_field_xss',
|
||||
),
|
||||
'filter' => array(
|
||||
'handler' => 'views_handler_filter_string',
|
||||
),
|
||||
);
|
||||
|
||||
$data['uc_payment_receipts']['received'] = array(
|
||||
'title' => t('Receipt date'),
|
||||
'help' => t('The date and time the payment was received.'),
|
||||
'field' => array(
|
||||
'handler' => 'views_handler_field_date',
|
||||
'click sortable' => TRUE,
|
||||
),
|
||||
'sort' => array(
|
||||
'handler' => 'views_handler_sort_date',
|
||||
),
|
||||
'filter' => array(
|
||||
'handler' => 'views_handler_filter_date',
|
||||
),
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Payment pack administration menu items.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Receives a check for an order and put in a clear date.
|
||||
*
|
||||
* @see uc_payment_pack_receive_check_form_submit()
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_payment_pack_receive_check_form($form, &$form_state, $order) {
|
||||
$balance = uc_payment_balance($order);
|
||||
$form['balance'] = array(
|
||||
'#prefix' => '<strong>' . t('Order balance:') . '</strong> ',
|
||||
'#markup' => uc_currency_format($balance),
|
||||
);
|
||||
$form['order_id'] = array(
|
||||
'#type' => 'hidden',
|
||||
'#value' => $order->order_id,
|
||||
);
|
||||
$form['amount'] = array(
|
||||
'#type' => 'uc_price',
|
||||
'#title' => t('Amount'),
|
||||
'#default_value' => $balance,
|
||||
);
|
||||
$form['comment'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Comment'),
|
||||
'#description' => t('Any notes about the check, like type or check number.'),
|
||||
'#size' => 64,
|
||||
'#maxlength' => 256,
|
||||
);
|
||||
$form['clear'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Expected clear date'),
|
||||
'#attributes' => array('class' => array('uc-inline-form', 'clearfix')),
|
||||
);
|
||||
$form['clear']['clear_month'] = uc_select_month(NULL, format_date(REQUEST_TIME, 'custom', 'n'));
|
||||
$form['clear']['clear_day'] = uc_select_day(NULL, format_date(REQUEST_TIME, 'custom', 'j'));
|
||||
$form['clear']['clear_year'] = uc_select_year(NULL, format_date(REQUEST_TIME, 'custom', 'Y'), format_date(REQUEST_TIME, 'custom', 'Y'), format_date(REQUEST_TIME, 'custom', 'Y') + 1);
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Receive check'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for uc_payment_pack_receive_check_form().
|
||||
*
|
||||
* @see uc_payment_pack_receive_check_form()
|
||||
*/
|
||||
function uc_payment_pack_receive_check_form_submit($form, &$form_state) {
|
||||
global $user;
|
||||
|
||||
uc_payment_enter($form_state['values']['order_id'], 'check', $form_state['values']['amount'], $user->uid, '', $form_state['values']['comment']);
|
||||
|
||||
db_insert('uc_payment_check')
|
||||
->fields(array(
|
||||
'order_id' => $form_state['values']['order_id'],
|
||||
'clear_date' => mktime(12, 0, 0, $form_state['values']['clear_month'], $form_state['values']['clear_day'], $form_state['values']['clear_year']),
|
||||
))
|
||||
->execute();
|
||||
|
||||
drupal_set_message(t('Check received, expected clear date of @date.', array('@date' => uc_date_format($form_state['values']['clear_month'], $form_state['values']['clear_day'], $form_state['values']['clear_year']))));
|
||||
|
||||
$form_state['redirect'] = 'admin/store/orders/' . $form_state['values']['order_id'];
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
name = Payment method pack
|
||||
description = Provides the check/money order, COD, and 'other' payment methods.
|
||||
dependencies[] = uc_cart
|
||||
dependencies[] = uc_payment
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_payment_pack module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function uc_payment_pack_schema() {
|
||||
$schema = array();
|
||||
|
||||
$schema['uc_payment_check'] = array(
|
||||
'description' => 'Stores check payment information.',
|
||||
'fields' => array(
|
||||
'check_id' => array(
|
||||
'description' => 'Primary key: the check ID.',
|
||||
'type' => 'serial',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
),
|
||||
'order_id' => array(
|
||||
'description' => 'The {uc_orders}.order_id.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'clear_date' => array(
|
||||
'description' => 'The Unix timestamp indicating the expected clear date for the check.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'order_id' => array('order_id'),
|
||||
),
|
||||
'primary key' => array('check_id'),
|
||||
'foreign keys' => array(
|
||||
'uc_orders' => array(
|
||||
'table' => 'uc_orders',
|
||||
'columns' => array('order_id' => 'order_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['uc_payment_cod'] = array(
|
||||
'description' => 'Stores COD payment information.',
|
||||
'fields' => array(
|
||||
'order_id' => array(
|
||||
'description' => 'The {uc_orders}.order_id.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'delivery_month' => array(
|
||||
'description' => 'The month of delivery. 1 => January, 2 => February, etc.',
|
||||
'type' => 'int',
|
||||
'size' => 'small',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'delivery_day' => array(
|
||||
'description' => 'The day of the month of delivery.',
|
||||
'type' => 'int',
|
||||
'size' => 'small',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'delivery_year' => array(
|
||||
'description' => 'The year of delivery.',
|
||||
'type' => 'int',
|
||||
'size' => 'small',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'primary key' => array('order_id'),
|
||||
'foreign keys' => array(
|
||||
'uc_orders' => array(
|
||||
'table' => 'uc_orders',
|
||||
'columns' => array('order_id' => 'order_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$schema['uc_payment_other'] = array(
|
||||
'description' => 'Stores Other payment type information.',
|
||||
'fields' => array(
|
||||
'order_id' => array(
|
||||
'description' => 'The {uc_orders}.order_id.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'description' => array(
|
||||
'description' => 'The description of the payment type.',
|
||||
'type' => 'varchar',
|
||||
'length' => 64,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
),
|
||||
'primary key' => array('order_id'),
|
||||
'foreign keys' => array(
|
||||
'uc_orders' => array(
|
||||
'table' => 'uc_orders',
|
||||
'columns' => array('order_id' => 'order_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_payment_pack_uninstall() {
|
||||
db_delete('variable')
|
||||
->condition(db_or()
|
||||
->condition('name', 'uc_check_%', 'LIKE')
|
||||
->condition('name', 'uc_cod_%', 'LIKE')
|
||||
)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function uc_payment_pack_update_last_removed() {
|
||||
return 6000;
|
||||
}
|
@@ -0,0 +1,395 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides the Check/Money Order, COD, and "Other" payment methods.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function uc_payment_pack_menu() {
|
||||
$items['admin/store/orders/%uc_order/receive_check'] = array(
|
||||
'title' => 'Receive check',
|
||||
'description' => 'Record details of a check that has been received.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('uc_payment_pack_receive_check_form', 3),
|
||||
'access arguments' => array('view all orders'),
|
||||
'file' => 'uc_payment_pack.admin.inc',
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uc_payment_method().
|
||||
*/
|
||||
function uc_payment_pack_uc_payment_method() {
|
||||
$methods['check'] = array(
|
||||
'name' => t('Check', array(), array('context' => 'cheque')),
|
||||
'title' => t('Check or money order'),
|
||||
'desc' => t('Pay by mailing a check or money order.'),
|
||||
'callback' => 'uc_payment_method_check',
|
||||
'weight' => 1,
|
||||
'checkout' => TRUE,
|
||||
'no_gateway' => TRUE,
|
||||
);
|
||||
$methods['cod'] = array(
|
||||
'name' => t('COD'),
|
||||
'title' => t('Cash on delivery'),
|
||||
'desc' => t('Pay cash on delivery on pick-up.'),
|
||||
'callback' => 'uc_payment_method_cod',
|
||||
'weight' => 1,
|
||||
'checkout' => FALSE,
|
||||
'no_gateway' => TRUE,
|
||||
);
|
||||
$methods['other'] = array(
|
||||
'name' => t('Other'),
|
||||
'title' => t('Other'),
|
||||
'desc' => t('A generic payment method type.'),
|
||||
'callback' => 'uc_payment_method_other',
|
||||
'weight' => 10,
|
||||
'checkout' => FALSE,
|
||||
'no_gateway' => TRUE,
|
||||
);
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment method callback for the generic payment method "Other".
|
||||
*/
|
||||
function uc_payment_method_other($op, &$order) {
|
||||
switch ($op) {
|
||||
case 'order-view':
|
||||
case 'customer-view':
|
||||
// Fetch the description for the payment entered by the administrator.
|
||||
if ($description = db_query('SELECT description FROM {uc_payment_other} WHERE order_id = :id', array(':id' => $order->order_id))->fetchField()) {
|
||||
return array('#markup' => t('Description: @desc', array('@desc' => $description)));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'order-details':
|
||||
$form['pm_other_description'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Description'),
|
||||
'#default_value' => isset($order->payment_details['description']) ? $order->payment_details['description'] : '',
|
||||
'#size' => 32,
|
||||
'#maxlength' => 64,
|
||||
);
|
||||
return $form;
|
||||
|
||||
case 'order-load':
|
||||
$description = db_query('SELECT description FROM {uc_payment_other} WHERE order_id = :id', array(':id' => $order->order_id))->fetchField();
|
||||
if (isset($description)) {
|
||||
$order->payment_details['description'] = $description;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'order-save':
|
||||
if (empty($order->payment_details['pm_other_description'])) {
|
||||
db_delete('uc_payment_other')
|
||||
->condition('order_id', $order->order_id)
|
||||
->execute();
|
||||
}
|
||||
else {
|
||||
db_merge('uc_payment_other')
|
||||
->key(array(
|
||||
'order_id' => $order->order_id,
|
||||
))
|
||||
->fields(array(
|
||||
'description' => $order->payment_details['pm_other_description'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment method callback for the "Cash on Delivery" payment method.
|
||||
*/
|
||||
function uc_payment_method_cod($op, &$order, $form = NULL, $form_state = NULL) {
|
||||
switch ($op) {
|
||||
case 'cart-details':
|
||||
$build['policy'] = array(
|
||||
'#markup' => '<p>' . variable_get('uc_cod_policy', t('Full payment is expected upon delivery or prior to pick-up.')) . '</p>'
|
||||
);
|
||||
|
||||
if (($max = variable_get('uc_cod_max_order', 0)) > 0 && is_numeric($max)) {
|
||||
$build['eligibility'] = array(
|
||||
'#markup' => '<p>' . t('Orders totalling more than !number are <b>not eligible</b> for COD.', array('!number' => uc_currency_format($max))) . '</p>'
|
||||
);
|
||||
}
|
||||
|
||||
if (variable_get('uc_cod_delivery_date', FALSE)) {
|
||||
$build += uc_payment_method_cod_form(array(), $form_state, $order);
|
||||
}
|
||||
return $build;
|
||||
|
||||
case 'cart-process':
|
||||
if (variable_get('uc_cod_delivery_date', FALSE)) {
|
||||
$order->payment_details = $form_state['values']['panes']['payment']['details'];
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case 'cart-review':
|
||||
$review = array();
|
||||
if (variable_get('uc_cod_delivery_date', FALSE)) {
|
||||
$date = uc_date_format(
|
||||
$order->payment_details['delivery_month'],
|
||||
$order->payment_details['delivery_day'],
|
||||
$order->payment_details['delivery_year']
|
||||
);
|
||||
$review[] = array('title' => t('Delivery date'), 'data' => $date);
|
||||
}
|
||||
return $review;
|
||||
|
||||
case 'order-view':
|
||||
case 'customer-view':
|
||||
$build = array('#markup' => '');
|
||||
if (variable_get('uc_cod_delivery_date', FALSE) &&
|
||||
isset($order->payment_details['delivery_month']) &&
|
||||
isset($order->payment_details['delivery_day']) &&
|
||||
isset($order->payment_details['delivery_year'])) {
|
||||
$build['#markup'] = t('Desired delivery date:') . '<br />' .
|
||||
uc_date_format(
|
||||
$order->payment_details['delivery_month'],
|
||||
$order->payment_details['delivery_day'],
|
||||
$order->payment_details['delivery_year']
|
||||
);
|
||||
}
|
||||
return $build;
|
||||
|
||||
case 'order-details':
|
||||
$build = array();
|
||||
if (variable_get('uc_cod_delivery_date', FALSE)) {
|
||||
$build = uc_payment_method_cod_form(array(), $form_state, $order);
|
||||
}
|
||||
return $build;
|
||||
|
||||
case 'order-load':
|
||||
$result = db_query('SELECT * FROM {uc_payment_cod} WHERE order_id = :id', array(':id' => $order->order_id));
|
||||
if ($row = $result->fetchObject()) {
|
||||
$order->payment_details = array(
|
||||
'delivery_month' => $row->delivery_month,
|
||||
'delivery_day' => $row->delivery_day,
|
||||
'delivery_year' => $row->delivery_year,
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'order-submit':
|
||||
if ($order->payment_method == 'cod' &&
|
||||
($max = variable_get('uc_cod_max_order', 0)) > 0 &&
|
||||
is_numeric($max) &&
|
||||
$order->order_total > $max) {
|
||||
$result[] = array(
|
||||
'pass' => FALSE,
|
||||
'message' => t('Your final order total exceeds the maximum for COD payment. Please go back and select a different method of payment.')
|
||||
);
|
||||
$_SESSION['expanded_panes'][] = 'payment';
|
||||
return $result;
|
||||
}
|
||||
// TODO: This falls through to the order-save case - is this deliberate?
|
||||
// If so, it should be documented.
|
||||
|
||||
case 'order-save':
|
||||
if (isset($order->payment_details['delivery_month']) &&
|
||||
isset($order->payment_details['delivery_day']) &&
|
||||
isset($order->payment_details['delivery_year']) ) {
|
||||
db_merge('uc_payment_cod')
|
||||
->key(array('order_id' => $order->order_id))
|
||||
->fields(array(
|
||||
'delivery_month' => $order->payment_details['delivery_month'],
|
||||
'delivery_day' => $order->payment_details['delivery_day'],
|
||||
'delivery_year' => $order->payment_details['delivery_year'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'order-delete':
|
||||
db_delete('uc_payment_cod')
|
||||
->condition('order_id', $order->order_id)
|
||||
->execute();
|
||||
break;
|
||||
|
||||
case 'settings':
|
||||
$form['uc_cod_policy'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Policy message'),
|
||||
'#default_value' => variable_get('uc_cod_policy', t('Full payment is expected upon delivery or prior to pick-up.')),
|
||||
'#description' => t('Help message shown at checkout.'),
|
||||
);
|
||||
$form['uc_cod_max_order'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Maximum order total eligible for COD'),
|
||||
'#default_value' => variable_get('uc_cod_max_order', 0),
|
||||
'#description' => t('Set to 0 for no maximum order limit.'),
|
||||
);
|
||||
$form['uc_cod_delivery_date'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Let customers enter a desired delivery date.'),
|
||||
'#default_value' => variable_get('uc_cod_delivery_date', FALSE),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect additional information for the "Cash on Delivery" payment method.
|
||||
*
|
||||
* @ingroup forms
|
||||
*/
|
||||
function uc_payment_method_cod_form($form, &$form_state, $order) {
|
||||
$month = !empty($order->payment_details['delivery_month']) ? $order->payment_details['delivery_month'] : format_date(REQUEST_TIME, 'custom', 'n');
|
||||
$day = !empty($order->payment_details['delivery_day']) ? $order->payment_details['delivery_day'] : format_date(REQUEST_TIME, 'custom', 'j');
|
||||
$year = !empty($order->payment_details['delivery_year']) ? $order->payment_details['delivery_year'] : format_date(REQUEST_TIME, 'custom', 'Y');
|
||||
|
||||
$form['description'] = array(
|
||||
'#markup' => '<div>' . t('Enter a desired delivery date:') . '</div>',
|
||||
);
|
||||
$form['delivery_month'] = uc_select_month(NULL, $month);
|
||||
$form['delivery_day'] = uc_select_day(NULL, $day);
|
||||
$form['delivery_year'] = uc_select_year(NULL, $year, format_date(REQUEST_TIME, 'custom', 'Y'), format_date(REQUEST_TIME, 'custom', 'Y') + 1);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment method callback for the "Check" payment method.
|
||||
*/
|
||||
function uc_payment_method_check($op, &$order, $form = NULL, &$form_state = NULL) {
|
||||
switch ($op) {
|
||||
case 'cart-details':
|
||||
$build['instructions'] = array(
|
||||
'#markup' => t('Checks should be made out to:')
|
||||
);
|
||||
|
||||
if (!variable_get('uc_check_mailing_street1', FALSE)) {
|
||||
$build['address'] = array(
|
||||
'#markup' => uc_address_format(
|
||||
uc_store_name(),
|
||||
NULL,
|
||||
variable_get('uc_store_company', ''),
|
||||
variable_get('uc_store_street1', ''),
|
||||
variable_get('uc_store_street2', ''),
|
||||
variable_get('uc_store_city', ''),
|
||||
variable_get('uc_store_zone', ''),
|
||||
variable_get('uc_store_postal_code', ''),
|
||||
variable_get('uc_store_country', 840)
|
||||
),
|
||||
'#prefix' => '<p>',
|
||||
'#suffix' => '</p>',
|
||||
);
|
||||
}
|
||||
else {
|
||||
$build['address'] = array(
|
||||
'#markup' => uc_address_format(
|
||||
variable_get('uc_check_mailing_name', ''),
|
||||
NULL,
|
||||
variable_get('uc_check_mailing_company', ''),
|
||||
variable_get('uc_check_mailing_street1', ''),
|
||||
variable_get('uc_check_mailing_street2', ''),
|
||||
variable_get('uc_check_mailing_city', ''),
|
||||
variable_get('uc_check_mailing_zone', ''),
|
||||
variable_get('uc_check_mailing_postal_code', ''),
|
||||
variable_get('uc_check_mailing_country', 840)
|
||||
),
|
||||
'#prefix' => '<p>',
|
||||
'#suffix' => '</p>',
|
||||
);
|
||||
}
|
||||
|
||||
$build['policy'] = array(
|
||||
'#markup' => '<p>' . variable_get('uc_check_policy', '') . '</p>'
|
||||
);
|
||||
return $build;
|
||||
|
||||
case 'cart-review':
|
||||
if (!variable_get('uc_check_mailing_street1', FALSE)) {
|
||||
$review[] = array(
|
||||
'title' => t('Mail to'),
|
||||
'data' => uc_address_format(
|
||||
uc_store_name(),
|
||||
NULL,
|
||||
variable_get('uc_store_company', ''),
|
||||
variable_get('uc_store_street1', ''),
|
||||
variable_get('uc_store_street2', ''),
|
||||
variable_get('uc_store_city', ''),
|
||||
variable_get('uc_store_zone', ''),
|
||||
variable_get('uc_store_postal_code', ''),
|
||||
variable_get('uc_store_country', 840)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$review[] = array(
|
||||
'title' => t('Mail to'),
|
||||
'data' => uc_address_format(
|
||||
variable_get('uc_check_mailing_name', ''),
|
||||
NULL,
|
||||
variable_get('uc_check_mailing_company', ''),
|
||||
variable_get('uc_check_mailing_street1', ''),
|
||||
variable_get('uc_check_mailing_street2', ''),
|
||||
variable_get('uc_check_mailing_city', ''),
|
||||
variable_get('uc_check_mailing_zone', ''),
|
||||
variable_get('uc_check_mailing_postal_code', ''),
|
||||
variable_get('uc_check_mailing_country', 840)
|
||||
)
|
||||
);
|
||||
}
|
||||
return $review;
|
||||
|
||||
case 'order-view':
|
||||
$build = array('#suffix' => '<br />');
|
||||
|
||||
$result = db_query('SELECT clear_date FROM {uc_payment_check} WHERE order_id = :id ', array(':id' => $order->order_id));
|
||||
if ($clear_date = $result->fetchField()) {
|
||||
$build['#markup'] = t('Clear Date:') . ' ' . format_date($clear_date, 'uc_store');
|
||||
}
|
||||
else {
|
||||
$build['#markup'] = l(t('Receive Check'), 'admin/store/orders/' . $order->order_id . '/receive_check');
|
||||
}
|
||||
return $build;
|
||||
|
||||
case 'customer-view':
|
||||
$build = array();
|
||||
$result = db_query('SELECT clear_date FROM {uc_payment_check} WHERE order_id = :id ', array(':id' => $order->order_id));
|
||||
if ($clear_date = $result->fetchField()) {
|
||||
$build['#markup'] = t('Check received') . '<br />' .
|
||||
t('Expected clear date:') . '<br />' . format_date($clear_date, 'uc_store');
|
||||
}
|
||||
return $build;
|
||||
|
||||
case 'settings':
|
||||
$form['check_address_info'] = array(
|
||||
'#markup' => '<div>' . t('Set the mailing address to display to customers who choose this payment method during checkout.') . '</div>',
|
||||
);
|
||||
$form['uc_check_mailing_name'] = uc_textfield(t('Contact'), variable_get('uc_check_mailing_name', ''), FALSE, t('Direct checks to a person or department.'), 128);
|
||||
$form['uc_check_address'] = array(
|
||||
'#type' => 'uc_address',
|
||||
'#default_value' => array(
|
||||
'uc_check_mailing_company' => variable_get('uc_check_mailing_company', ''),
|
||||
'uc_check_mailing_street1' => variable_get('uc_check_mailing_street1', ''),
|
||||
'uc_check_mailing_street2' => variable_get('uc_check_mailing_street2', ''),
|
||||
'uc_check_mailing_city' => variable_get('uc_check_mailing_city', ''),
|
||||
'uc_check_mailing_zone' => variable_get('uc_check_mailing_zone', ''),
|
||||
'uc_check_mailing_country' => isset($form_state['values']['uc_check_mailing_country']) ? $form_state['values']['uc_check_mailing_country'] : variable_get('uc_check_mailing_country', ''),
|
||||
'uc_check_mailing_postal_code' => variable_get('uc_check_mailing_postal_code', ''),
|
||||
),
|
||||
'#required' => FALSE,
|
||||
'#key_prefix' => 'uc_check_mailing',
|
||||
);
|
||||
$form['uc_check_policy'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Check payment policy', array(), array('context' => 'cheque')),
|
||||
'#description' => t('Instructions for customers on the checkout page.'),
|
||||
'#default_value' => variable_get('uc_check_policy', t('Personal and business checks will be held for up to 10 business days to ensure payment clears before an order is shipped.')),
|
||||
'#rows' => 3,
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Variable module hook implementations.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_variable_group_info().
|
||||
*/
|
||||
function uc_payment_pack_variable_group_info() {
|
||||
$groups['uc_payment_pack'] = array(
|
||||
'title' => t('Ubercart payment pack settings'),
|
||||
'access' => 'administer store',
|
||||
'path' => array('admin/store/settings/payment/method'),
|
||||
);
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_variable_info().
|
||||
*/
|
||||
function uc_payment_pack_variable_info($options) {
|
||||
$variables['uc_cod_policy'] = array(
|
||||
'type' => 'text',
|
||||
'title' => t('COD policy message', array(), $options),
|
||||
'description' => t('Policy message for Cash On Delivery', array(), $options),
|
||||
'group' => 'uc_payment_pack',
|
||||
'default' => t('Full payment is expected upon delivery or prior to pick-up.', array(), $options),
|
||||
);
|
||||
$variables['uc_check_policy'] = array(
|
||||
'type' => 'text',
|
||||
'title' => t('Check payment policy', array(), $options),
|
||||
'description' => t('Instructions for customers on the checkout page.', array(), $options),
|
||||
'group' => 'uc_payment_pack',
|
||||
'default' => t('Personal and business checks will be held for up to 10 business days to ensure payment clears before an order is shipped.', array(), $options),
|
||||
);
|
||||
return $variables;
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
name = PayPal
|
||||
description = Processes payments using PayPal Website Payments Standard, Website Payments Pro and Express Checkout.
|
||||
dependencies[] = uc_payment
|
||||
package = Ubercart - payment
|
||||
core = 7.x
|
||||
|
||||
; Information added by Drupal.org packaging script on 2013-12-17
|
||||
version = "7.x-3.6"
|
||||
core = "7.x"
|
||||
project = "ubercart"
|
||||
datestamp = "1387304010"
|
||||
|
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Install, update and uninstall functions for the uc_paypal module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_requirements().
|
||||
*/
|
||||
function uc_paypal_requirements($phase) {
|
||||
$requirements = array();
|
||||
$t = get_t();
|
||||
|
||||
$has_curl = function_exists('curl_init');
|
||||
|
||||
// PayPal WPP requires cURL.
|
||||
if (variable_get('uc_pg_paypal_wpp_enabled', TRUE)) {
|
||||
$requirements['uc_paypal_curl'] = array(
|
||||
'title' => $t('cURL'),
|
||||
'value' => $has_curl ? $t('Enabled') : $t('Not found'),
|
||||
);
|
||||
if (!$has_curl) {
|
||||
$requirements['uc_paypal_curl']['severity'] = REQUIREMENT_ERROR;
|
||||
$requirements['uc_paypal_curl']['description'] = $t("PayPal WPP requires the PHP <a href='!curl_url'>cURL</a> library.", array('!curl_url' => 'http://php.net/manual/en/curl.setup.php'));
|
||||
}
|
||||
}
|
||||
|
||||
return $requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function uc_paypal_schema() {
|
||||
$schema = array();
|
||||
|
||||
$schema['uc_payment_paypal_ipn'] = array(
|
||||
'description' => 'Logs PayPal Instant Payment Notifications.',
|
||||
'fields' => array(
|
||||
'order_id' => array(
|
||||
'description' => 'The order ID.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
'txn_id' => array(
|
||||
'description' => 'The transaction ID from PayPal.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'txn_type' => array(
|
||||
'description' => 'The transaction type from PayPal.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'mc_gross' => array(
|
||||
'description' => 'The payment amount from PayPal.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'status' => array(
|
||||
'description' => 'The IPN status from PayPal.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'receiver_email' => array(
|
||||
'description' => 'The e-mail address of the PayPal account.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'payer_email' => array(
|
||||
'description' => 'The e-mail address of the buyer.',
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
),
|
||||
'received' => array(
|
||||
'description' => 'The IPN receipt timestamp.',
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
),
|
||||
),
|
||||
'indexes' => array(
|
||||
'order_id' => array('order_id'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'uc_orders' => array(
|
||||
'table' => 'uc_orders',
|
||||
'columns' => array('order_id' => 'order_id'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function uc_paypal_install() {
|
||||
$t = get_t();
|
||||
|
||||
db_merge('uc_order_statuses')
|
||||
->key(array('order_status_id' => 'paypal_pending'))
|
||||
->insertFields(array(
|
||||
'order_status_id' => 'paypal_pending',
|
||||
'title' => $t('PayPal pending'),
|
||||
'state' => 'post_checkout',
|
||||
'weight' => 7,
|
||||
'locked' => 1,
|
||||
))
|
||||
->updateFields(array(
|
||||
'state' => 'post_checkout',
|
||||
'locked' => 1,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function uc_paypal_uninstall() {
|
||||
db_update('uc_order_statuses')
|
||||
->fields(array(
|
||||
'locked' => 0,
|
||||
))
|
||||
->condition('order_status_id', 'paypal_pending')
|
||||
->execute();
|
||||
|
||||
db_delete('variable')
|
||||
->condition('name', 'uc_paypal_%', 'LIKE')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function uc_paypal_update_last_removed() {
|
||||
// 7.x-3.0-beta2 and earlier were installed with schema version 0,
|
||||
// which causes update.php to fail.
|
||||
return drupal_get_installed_schema_version('uc_paypal') == 0 ? 0 : 6000;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removed completely unnecessary update 7000.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fix incorrect order status configuration.
|
||||
*/
|
||||
function uc_paypal_update_7001() {
|
||||
db_delete('uc_order_statuses')
|
||||
->condition('order_status_id', '')
|
||||
->execute();
|
||||
|
||||
db_merge('uc_order_statuses')
|
||||
->key(array('order_status_id' => 'paypal_pending'))
|
||||
->insertFields(array(
|
||||
'order_status_id' => 'paypal_pending',
|
||||
'title' => t('PayPal pending'),
|
||||
'state' => 'payment_received',
|
||||
'weight' => 7,
|
||||
'locked' => 1,
|
||||
))
|
||||
->updateFields(array(
|
||||
'state' => 'payment_received',
|
||||
'locked' => 1,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix incorrect order state configuration.
|
||||
*/
|
||||
function uc_paypal_update_7300() {
|
||||
db_update('uc_order_statuses')
|
||||
->fields(array(
|
||||
'state' => 'post_checkout',
|
||||
))
|
||||
->condition('order_status_id', 'paypal_pending')
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unused variable.
|
||||
*/
|
||||
function uc_paypal_update_7301() {
|
||||
variable_del('uc_paypal_wps_checkout_button');
|
||||
}
|
@@ -0,0 +1,447 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Paypal administration menu items.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Processes Instant Payment Notifiations from PayPal.
|
||||
*/
|
||||
function uc_paypal_ipn() {
|
||||
if (!isset($_POST['invoice'])) {
|
||||
watchdog('uc_paypal', 'IPN attempted with invalid order ID.', array(), WATCHDOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strpos($_POST['invoice'], '-') > 0) {
|
||||
list($order_id, $cart_id) = explode('-', $_POST['invoice']);
|
||||
|
||||
// Sanitize order ID and cart ID
|
||||
$order_id = intval($order_id);
|
||||
$cart_id = check_plain($cart_id);
|
||||
|
||||
if (!empty($cart_id)) {
|
||||
// Needed later by uc_complete_sale to empty the correct cart
|
||||
$_SESSION['uc_cart_id'] = $cart_id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$order_id = intval($_POST['invoice']);
|
||||
}
|
||||
|
||||
watchdog('uc_paypal', 'Receiving IPN at URL for order @order_id. <pre>@debug</pre>', array('@order_id' => $order_id, '@debug' => variable_get('uc_paypal_wps_debug_ipn', FALSE) ? print_r($_POST, TRUE) : ''));
|
||||
|
||||
$order = uc_order_load($order_id);
|
||||
|
||||
if ($order == FALSE) {
|
||||
watchdog('uc_paypal', 'IPN attempted for non-existent order @order_id.', array('@order_id' => $order_id), WATCHDOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Assign posted variables to local variables
|
||||
$payment_status = check_plain($_POST['payment_status']);
|
||||
$payment_amount = check_plain($_POST['mc_gross']);
|
||||
$payment_currency = check_plain($_POST['mc_currency']);
|
||||
$receiver_email = check_plain($_POST['business']);
|
||||
if ($receiver_email == '') {
|
||||
$receiver_email = check_plain($_POST['receiver_email']);
|
||||
}
|
||||
$txn_id = check_plain($_POST['txn_id']);
|
||||
$txn_type = check_plain($_POST['txn_type']);
|
||||
$payer_email = check_plain($_POST['payer_email']);
|
||||
|
||||
// Express Checkout IPNs may not have the WPS email stored. But if it is,
|
||||
// make sure that the right account is being paid.
|
||||
$uc_paypal_wps_email = trim(variable_get('uc_paypal_wps_email', ''));
|
||||
if (!empty($uc_paypal_wps_email) && drupal_strtolower($receiver_email) != drupal_strtolower($uc_paypal_wps_email)) {
|
||||
watchdog('uc_paypal', 'IPN for a different PayPal account attempted.', array(), WATCHDOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$req = '';
|
||||
|
||||
foreach ($_POST as $key => $value) {
|
||||
$value = urlencode(stripslashes($value));
|
||||
$req .= $key . '=' . $value . '&';
|
||||
}
|
||||
|
||||
$req .= 'cmd=_notify-validate';
|
||||
|
||||
if (variable_get('uc_paypal_wpp_server', '') == 'https://api-3t.paypal.com/nvp') {
|
||||
$host = 'https://www.paypal.com/cgi-bin/webscr';
|
||||
}
|
||||
else {
|
||||
$host = variable_get('uc_paypal_wps_server', 'https://www.sandbox.paypal.com/cgi-bin/webscr');
|
||||
}
|
||||
|
||||
$response = drupal_http_request($host, array(
|
||||
'method' => 'POST',
|
||||
'data' => $req,
|
||||
));
|
||||
|
||||
// TODO: Change this to property_exists when we have a PHP requirement >= 5.1.
|
||||
if (array_key_exists('error', $response)) {
|
||||
watchdog('uc_paypal', 'IPN failed with HTTP error @error, code @code.', array('@error' => $response->error, '@code' => $response->code), WATCHDOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp($response->data, 'VERIFIED') == 0) {
|
||||
watchdog('uc_paypal', 'IPN transaction verified.');
|
||||
|
||||
$duplicate = (bool) db_query_range('SELECT 1 FROM {uc_payment_paypal_ipn} WHERE txn_id = :id AND status <> :status', 0, 1, array(':id' => $txn_id, ':status' => 'Pending'))->fetchField();
|
||||
if ($duplicate) {
|
||||
if ($order->payment_method != 'credit') {
|
||||
watchdog('uc_paypal', 'IPN transaction ID has been processed before.', array(), WATCHDOG_NOTICE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
db_insert('uc_payment_paypal_ipn')
|
||||
->fields(array(
|
||||
'order_id' => $order_id,
|
||||
'txn_id' => $txn_id,
|
||||
'txn_type' => $txn_type,
|
||||
'mc_gross' => $payment_amount,
|
||||
'status' => $payment_status,
|
||||
'receiver_email' => $receiver_email,
|
||||
'payer_email' => $payer_email,
|
||||
'received' => REQUEST_TIME,
|
||||
))
|
||||
->execute();
|
||||
|
||||
switch ($payment_status) {
|
||||
case 'Canceled_Reversal':
|
||||
uc_order_comment_save($order_id, 0, t('PayPal has canceled the reversal and returned !amount !currency to your account.', array('!amount' => uc_currency_format($payment_amount, FALSE), '!currency' => $payment_currency)), 'admin');
|
||||
break;
|
||||
|
||||
case 'Completed':
|
||||
if (abs($payment_amount - $order->order_total) > 0.01) {
|
||||
watchdog('uc_paypal', 'Payment @txn_id for order @order_id did not equal the order total.', array('@txn_id' => $txn_id, '@order_id' => $order->order_id), WATCHDOG_WARNING, l(t('view'), 'admin/store/orders/' . $order->order_id));
|
||||
}
|
||||
$comment = t('PayPal transaction ID: @txn_id', array('@txn_id' => $txn_id));
|
||||
uc_payment_enter($order_id, 'paypal_wps', $payment_amount, $order->uid, NULL, $comment);
|
||||
uc_cart_complete_sale($order);
|
||||
uc_order_comment_save($order_id, 0, t('PayPal IPN reported a payment of @amount @currency.', array('@amount' => uc_currency_format($payment_amount, FALSE), '@currency' => $payment_currency)));
|
||||
break;
|
||||
|
||||
case 'Denied':
|
||||
uc_order_comment_save($order_id, 0, t("You have denied the customer's payment."), 'admin');
|
||||
break;
|
||||
|
||||
case 'Expired':
|
||||
uc_order_comment_save($order_id, 0, t('The authorization has failed and cannot be captured.'), 'admin');
|
||||
break;
|
||||
|
||||
case 'Failed':
|
||||
uc_order_comment_save($order_id, 0, t("The customer's attempted payment from a bank account failed."), 'admin');
|
||||
break;
|
||||
|
||||
case 'Pending':
|
||||
uc_order_update_status($order_id, 'paypal_pending');
|
||||
uc_order_comment_save($order_id, 0, t('Payment is pending at PayPal: @reason', array('@reason' => _uc_paypal_pending_message(check_plain($_POST['pending_reason'])))), 'admin');
|
||||
break;
|
||||
|
||||
// You, the merchant, refunded the payment.
|
||||
case 'Refunded':
|
||||
$comment = t('PayPal transaction ID: @txn_id', array('@txn_id' => $txn_id));
|
||||
uc_payment_enter($order_id, 'paypal_wps', $payment_amount, $order->uid, NULL, $comment);
|
||||
break;
|
||||
|
||||
case 'Reversed':
|
||||
watchdog('uc_paypal', 'PayPal has reversed a payment!', array(), WATCHDOG_ERROR);
|
||||
uc_order_comment_save($order_id, 0, t('Payment has been reversed by PayPal: @reason', array('@reason' => _uc_paypal_reversal_message(check_plain($_POST['reason_code'])))), 'admin');
|
||||
break;
|
||||
|
||||
case 'Processed':
|
||||
uc_order_comment_save($order_id, 0, t('A payment has been accepted.'), 'admin');
|
||||
break;
|
||||
|
||||
case 'Voided':
|
||||
uc_order_comment_save($order_id, 0, t('The authorization has been voided.'), 'admin');
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif (strcmp($response->data, 'INVALID') == 0) {
|
||||
watchdog('uc_paypal', 'IPN transaction failed verification.', array(), WATCHDOG_ERROR);
|
||||
uc_order_comment_save($order_id, 0, t('An IPN transaction failed verification for this order.'), 'admin');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the review page for Express Checkout Mark Flow.
|
||||
*/
|
||||
function uc_paypal_ec_review_redirect() {
|
||||
if (!isset($_SESSION['TOKEN']) || ($order = uc_order_load($_SESSION['cart_order'])) == FALSE) {
|
||||
unset($_SESSION['cart_order']);
|
||||
unset($_SESSION['have_details']);
|
||||
unset($_SESSION['TOKEN'], $_SESSION['PAYERID']);
|
||||
drupal_set_message(t('An error has occurred in your PayPal payment. Please review your cart and try again.'));
|
||||
drupal_goto('cart');
|
||||
}
|
||||
|
||||
$nvp_request = array(
|
||||
'METHOD' => 'GetExpressCheckoutDetails',
|
||||
'TOKEN' => $_SESSION['TOKEN'],
|
||||
);
|
||||
|
||||
$nvp_response = uc_paypal_api_request($nvp_request, variable_get('uc_paypal_wpp_server', 'https://api-3t.sandbox.paypal.com/nvp'));
|
||||
|
||||
$_SESSION['PAYERID'] = $nvp_response['PAYERID'];
|
||||
|
||||
drupal_goto('cart/checkout/review');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the review page for Express Checkout Shortcut Flow.
|
||||
*/
|
||||
function uc_paypal_ec_review() {
|
||||
if (!isset($_SESSION['TOKEN']) || ($order = uc_order_load($_SESSION['cart_order'])) == FALSE) {
|
||||
unset($_SESSION['cart_order']);
|
||||
unset($_SESSION['have_details']);
|
||||
unset($_SESSION['TOKEN'], $_SESSION['PAYERID']);
|
||||
drupal_set_message(t('An error has occurred in your PayPal payment. Please review your cart and try again.'));
|
||||
drupal_goto('cart');
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['have_details'][$order->order_id])) {
|
||||
$nvp_request = array(
|
||||
'METHOD' => 'GetExpressCheckoutDetails',
|
||||
'TOKEN' => $_SESSION['TOKEN'],
|
||||
);
|
||||
|
||||
$nvp_response = uc_paypal_api_request($nvp_request, variable_get('uc_paypal_wpp_server', 'https://api-3t.sandbox.paypal.com/nvp'));
|
||||
|
||||
$_SESSION['PAYERID'] = $nvp_response['PAYERID'];
|
||||
|
||||
$shipname = check_plain($nvp_response['SHIPTONAME']);
|
||||
if (strpos($shipname, ' ') > 0) {
|
||||
$order->delivery_first_name = substr($shipname, 0, strrpos(trim($shipname), ' '));
|
||||
$order->delivery_last_name = substr($shipname, strrpos(trim($shipname), ' ') + 1);
|
||||
}
|
||||
else {
|
||||
$order->delivery_first_name = $shipname;
|
||||
$order->delivery_last_name = '';
|
||||
}
|
||||
|
||||
$country_id = db_query("SELECT country_id FROM {uc_countries} WHERE country_iso_code_2 = :code", array(':code' => $nvp_response['SHIPTOCOUNTRYCODE']))->fetchField();
|
||||
$zone_id = 0;
|
||||
|
||||
if (!empty($country_id) && isset($nvp_response['SHIPTOSTATE'])) {
|
||||
$zone = $nvp_response['SHIPTOSTATE'];
|
||||
$zone_id = db_query("SELECT zone_id FROM {uc_zones} WHERE zone_country_id = :id AND (zone_code = :code OR zone_name = :name)", array(':id' => $country_id, ':code' => $zone, ':name' => $zone))->fetchField();
|
||||
}
|
||||
|
||||
$order->delivery_street1 = check_plain($nvp_response['SHIPTOSTREET']);
|
||||
$order->delivery_street2 = isset($nvp_response['SHIPTOSTREET2']) ? check_plain($nvp_response['SHIPTOSTREET2']) : '';
|
||||
$order->delivery_city = check_plain($nvp_response['SHIPTOCITY']);
|
||||
$order->delivery_zone = !empty($zone_id) ? $zone_id : 0;
|
||||
$order->delivery_postal_code = check_plain($nvp_response['SHIPTOZIP']);
|
||||
$order->delivery_country = !empty($country_id) ? $country_id : 840;
|
||||
|
||||
$order->billing_first_name = check_plain($nvp_response['FIRSTNAME']);
|
||||
$order->billing_last_name = check_plain($nvp_response['LASTNAME']);
|
||||
$order->billing_street1 = check_plain($nvp_response['EMAIL']);
|
||||
|
||||
if (empty($order->primary_email)) {
|
||||
$order->primary_email = $nvp_response['EMAIL'];
|
||||
}
|
||||
$order->payment_method = 'paypal_ec';
|
||||
|
||||
uc_order_save($order);
|
||||
|
||||
$_SESSION['have_details'][$order->order_id] = TRUE;
|
||||
}
|
||||
|
||||
$build['instructions'] = array('#markup' => t("Your order is almost complete! Please fill in the following details and click 'Continue checkout' to finalize the purchase."));
|
||||
|
||||
$build['form'] = drupal_get_form('uc_paypal_ec_review_form', $order);
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the form for the custom Review Payment screen for Express Checkout.
|
||||
*/
|
||||
function uc_paypal_ec_review_form($form, &$form_state, $order) {
|
||||
if (module_exists('uc_quote') && variable_get('uc_paypal_ec_review_shipping', TRUE) && uc_order_is_shippable($order)) {
|
||||
uc_checkout_pane_quotes('prepare', $order, NULL);
|
||||
$order->line_items = uc_order_load_line_items($order);
|
||||
uc_order_save($order);
|
||||
|
||||
$result = uc_checkout_pane_quotes('view', $order, NULL);
|
||||
$form['panes']['quotes'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Shipping cost'),
|
||||
'#collapsible' => FALSE,
|
||||
);
|
||||
$form['panes']['quotes'] += $result['contents'];
|
||||
unset($form['panes']['quotes']['quote_button']);
|
||||
|
||||
$form['shippable'] = array('#type' => 'value', '#value' => 'true');
|
||||
}
|
||||
|
||||
if (variable_get('uc_paypal_ec_review_company', TRUE)) {
|
||||
$form['delivery_company'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => uc_get_field_name('company'),
|
||||
'#description' => uc_order_is_shippable($order) ? t('Leave blank if shipping to a residence.') : '',
|
||||
'#default_value' => $order->delivery_company,
|
||||
);
|
||||
}
|
||||
|
||||
if (variable_get('uc_paypal_ec_review_phone', TRUE)) {
|
||||
$form['delivery_phone'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Contact phone number'),
|
||||
'#default_value' => $order->delivery_phone,
|
||||
'#size' => 24,
|
||||
);
|
||||
}
|
||||
|
||||
if (variable_get('uc_paypal_ec_review_comment', TRUE)) {
|
||||
$form['order_comments'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Order comments'),
|
||||
'#description' => t('Special instructions or notes regarding your order.'),
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($form)) {
|
||||
drupal_goto('cart/echeckout/submit');
|
||||
}
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Continue checkout'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
function uc_paypal_ec_review_form_validate($form, &$form_state) {
|
||||
if (!empty($form_state['values']['shippable']) && empty($form_state['values']['quotes']['quote_option'])) {
|
||||
form_set_error('shipping', t('You must calculate and select a shipping option.'));
|
||||
}
|
||||
}
|
||||
|
||||
function uc_paypal_ec_review_form_submit($form, &$form_state) {
|
||||
$order = uc_order_load($_SESSION['cart_order']);
|
||||
|
||||
if (!empty($form_state['values']['shippable'])) {
|
||||
$quote_option = explode('---', $form_state['values']['quotes']['quote_option']);
|
||||
$order->quote['method'] = $quote_option[0];
|
||||
$order->quote['accessorials'] = $quote_option[1];
|
||||
$methods = uc_quote_methods();
|
||||
$method = $methods[$quote_option[0]];
|
||||
|
||||
$label = $method['quote']['accessorials'][$quote_option[1]];
|
||||
|
||||
$quote_option = $form_state['values']['quotes']['quote_option'];
|
||||
$order->quote['rate'] = $form_state['values']['quotes'][$quote_option]['rate'];
|
||||
|
||||
$result = db_query("SELECT line_item_id FROM {uc_order_line_items} WHERE order_id = :id AND type = :type", array(':id' => $order->order_id, ':type' => 'shipping'));
|
||||
if ($lid = $result->fetchField()) {
|
||||
uc_order_update_line_item($lid, $label, $order->quote['rate']);
|
||||
}
|
||||
else {
|
||||
uc_order_line_item_add($order->order_id, 'shipping', $label, $order->quote['rate']);
|
||||
}
|
||||
}
|
||||
|
||||
if (variable_get('uc_paypal_ec_review_company', TRUE)) {
|
||||
$order->delivery_company = $form_state['values']['delivery_company'];
|
||||
}
|
||||
|
||||
if (variable_get('uc_paypal_ec_review_phone', TRUE)) {
|
||||
$order->delivery_phone = $form_state['values']['delivery_phone'];
|
||||
}
|
||||
|
||||
if (variable_get('uc_paypal_ec_review_comment', TRUE)) {
|
||||
db_delete('uc_order_comments')
|
||||
->condition('order_id', $order->order_id)
|
||||
->execute();
|
||||
uc_order_comment_save($order->order_id, 0, $form_state['values']['order_comments'], 'order');
|
||||
}
|
||||
|
||||
uc_order_save($order);
|
||||
|
||||
$form_state['redirect'] = 'cart/echeckout/submit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents the final total to the user for checkout!
|
||||
*/
|
||||
function uc_paypal_ec_submit() {
|
||||
if (!isset($_SESSION['TOKEN']) || ($order = uc_order_load($_SESSION['cart_order'])) == FALSE) {
|
||||
unset($_SESSION['cart_order'], $_SESSION['have_details']);
|
||||
unset($_SESSION['TOKEN'], $_SESSION['PAYERID']);
|
||||
drupal_set_message(t('An error has occurred in your PayPal payment. Please review your cart and try again.'));
|
||||
drupal_goto('cart');
|
||||
}
|
||||
|
||||
drupal_add_css(drupal_get_path('module', 'uc_cart') . '/uc_cart.css');
|
||||
|
||||
$build['review'] = array(
|
||||
'#theme' => 'uc_cart_review_table',
|
||||
'#items' => $order->products,
|
||||
'#show_subtotal' => FALSE,
|
||||
);
|
||||
|
||||
$build['line_items'] = uc_order_pane_line_items('customer', $order);
|
||||
|
||||
$build['instructions'] = array('#markup' => '<p>' . t("Your order is not complete until you click the 'Submit order' button below. Your PayPal account will be charged for the amount shown above once your order is placed. You will receive confirmation once your payment is complete.") . '</p>');
|
||||
|
||||
$build['submit_form'] = drupal_get_form('uc_paypal_ec_submit_form');
|
||||
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits an order, calling the NVP API to send the order total to PayPal.
|
||||
*/
|
||||
function uc_paypal_ec_submit_form($form, &$form_state) {
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit order'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a complete Website Payments Standard sale.
|
||||
*/
|
||||
function uc_paypal_complete($order) {
|
||||
// If the order ID specified in the return URL is not the same as the one in
|
||||
// the user's session, we need to assume this is either a spoof or that the
|
||||
// user tried to adjust the order on this side while at PayPal. If it was a
|
||||
// legitimate checkout, the IPN will still come in from PayPal so the order
|
||||
// gets processed correctly. We'll leave an ambiguous message just in case.
|
||||
if (!isset($_SESSION['cart_order']) || intval($_SESSION['cart_order']) != $order->order_id) {
|
||||
drupal_set_message(t('Thank you for your order! PayPal will notify us once your payment has been processed.'));
|
||||
drupal_goto('cart');
|
||||
}
|
||||
|
||||
// Ensure the payment method is PayPal WPS.
|
||||
if ($order->payment_method != 'paypal_wps') {
|
||||
drupal_goto('cart');
|
||||
}
|
||||
|
||||
// This lets us know it's a legitimate access of the complete page.
|
||||
$_SESSION['uc_checkout'][$_SESSION['cart_order']]['do_complete'] = TRUE;
|
||||
drupal_goto('cart/checkout/complete');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a canceled Website Payments Standard sale.
|
||||
*/
|
||||
function uc_paypal_cancel() {
|
||||
unset($_SESSION['cart_order']);
|
||||
|
||||
drupal_set_message(t('Your PayPal payment was canceled. Please feel free to continue shopping or contact us for assistance.'));
|
||||
|
||||
drupal_goto(variable_get('uc_paypal_wps_cancel_return_url', 'cart'));
|
||||
}
|