'Payment settings',
'description' => 'Configure the payment settings.',
'page callback' => 'uc_payment_settings_overview',
'access arguments' => array('administer store'),
'file' => 'uc_payment.admin.inc',
);
$items['admin/store/settings/payment/overview'] = array(
'title' => 'Overview',
'description' => 'View the payment settings.',
'access arguments' => array('administer store'),
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/store/settings/payment/edit'] = array(
'title' => 'Edit',
'description' => 'Edit the payment settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array('uc_payment_settings_form'),
'access arguments' => array('administer store'),
'weight' => -5,
'type' => MENU_LOCAL_TASK,
'file' => 'uc_payment.admin.inc',
);
$items['admin/store/settings/payment/edit/basic'] = array(
'title' => 'Payment settings',
'description' => 'Edit the basic payment settings.',
'access arguments' => array('administer store'),
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/store/settings/payment/edit/methods'] = array(
'title' => 'Payment methods',
'description' => 'Edit the payment method settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array('uc_payment_methods_form'),
'access arguments' => array('administer store'),
'weight' => -5,
'type' => MENU_LOCAL_TASK,
'file' => 'uc_payment.admin.inc',
);
$items['admin/store/settings/payment/edit/gateways'] = array(
'title' => 'Payment gateways',
'description' => 'Edit the payment gateway settings.',
'access arguments' => array('administer store'),
'page callback' => 'drupal_get_form',
'page arguments' => array('uc_payment_gateways_form'),
'weight' => 0,
'type' => MENU_LOCAL_TASK,
'file' => 'uc_payment.admin.inc',
);
$items['admin/store/orders/%uc_order/payment_details/%'] = array(
'title' => 'Payment details',
'description' => 'Add the payment details to the order pane.',
'page callback' => 'uc_payment_get_details',
'page arguments' => array(5, 'order', 3),
'access arguments' => array('edit orders'),
'type' => MENU_CALLBACK,
);
$items['admin/store/orders/%uc_order/payments/select/%'] = array(
'title' => 'Select payment gateway',
'page callback' => 'uc_payment_gateway_select',
'access arguments' => array('view all orders'),
'type' => MENU_CALLBACK,
'file' => 'uc_payment.admin.inc',
);
$items['admin/store/orders/%uc_order/payments'] = array(
'title' => 'Payments',
'page callback' => 'drupal_get_form',
'page arguments' => array('uc_payment_by_order_form', 3),
'access callback' => 'uc_payment_tracking_access',
'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 callback' => 'uc_payment_delete_access',
'type' => MENU_CALLBACK,
'file' => 'uc_payment.admin.inc',
);
return $items;
}
/**
* 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'),
),
);
}
/**
* Access callback to view list of payments.
*/
function uc_payment_tracking_access() {
return user_access('view payments') && variable_get('uc_payment_tracking', TRUE);
}
/**
* Access callback to delete a payment.
*/
function uc_payment_delete_access() {
return user_access('delete payments') && variable_get('uc_payment_deleting', TRUE);
}
/**
* Implements hook_theme().
*/
function uc_payment_theme() {
return array(
'uc_payment_totals' => array(
'variables' => array('order' => NULL),
),
'uc_payment_method_table' => array(
'render element' => 'form',
'file' => 'uc_payment.admin.inc',
),
'uc_payment_by_order_form' => array(
'render element' => 'form',
'file' => 'uc_payment.admin.inc',
),
'uc_payment_method_select' => array(
'render element' => 'form',
),
);
}
/**
* Implements hook_init().
*/
function uc_payment_init() {
global $conf;
$conf['i18n_variables'][] = 'uc_default_payment_msg';
}
/*******************************************************************************
* Hook Functions (Ubercart)
******************************************************************************/
/**
* 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[] = array(
'id' => 'payment',
'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[] = array(
'id' => 'payment',
'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[] = array(
'id' => 'payment_received',
'title' => t('Payment received'),
'weight' => 10,
'scope' => 'general',
);
return $states;
}
/*******************************************************************************
* Callback Functions, Forms, and Tables
******************************************************************************/
/**
* Return 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) {
return $form['panes']['payment']['line_items'];
}
/**
* @ingroup themeable
*/
function theme_uc_payment_totals($variables) {
$order = $variables['order'];
$output = t('Order total preview:') . '
';
$grand_total = 0;
foreach ($order->line_items as $line) {
if (!empty($line['title'])) {
$output .= '' . filter_xss($line['title']) . ': | '
. '' . theme('uc_price', array('price' => $line['amount'])) . ' |
';
}
}
$output .= '' . t('Order total:') . ' | '
. '' . theme('uc_price', array('price' => uc_order_get_total($order)))
. ' |
';
return $output;
}
function uc_payment_get_details($method_id, $view = 'cart', $order = NULL) {
if ($view == 'cart') {
if (!($order = uc_order_load($_SESSION['cart_order']))) {
$_SESSION['cart_order'] = NULL;
$order = NULL;
}
if ($order->order_status != 0 || ($user->uid && $user->uid != $order->uid)) {
$order = NULL;
}
}
$func = _uc_payment_method_data($method_id, 'callback');
if (function_exists($func)) {
$output = $func($view . '-details', $order);
}
print drupal_render($output);
exit();
}
function _uc_payment_total_sort($a, $b) {
if ($a[0] == $b[0]) {
return 0;
}
return ($a[0] < $b[0]) ? -1 : 1;
}
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;
}
/*******************************************************************************
* Module and Helper Functions
******************************************************************************/
/**
* Process 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;
}
// If we only found one gateway for this payment method...
if (count($gateways) == 1) {
// Get the right key for the payment gateway in the array.
$key = array_shift(array_keys($gateways));
// If we can find a callback in the gateway for the payment method...
if (function_exists($gateways[$key][$method])) {
// Pass the payment data onto the callback and store the result.
$result = $gateways[$key][$method]($order_id, $amount, $data);
}
else {
// Otherwise display a failure message to administrators.
if (user_access('administer store')) {
drupal_set_message(t("Attempted to process a %type payment but the gateway's function was not found."));
}
$result['success'] = FALSE;
}
}
else {
// Otherwise attempt to find the appropriate gateway function in the array.
$callback = FALSE;
foreach ($gateways as $gateway) {
// If we want the default gateway and this is it, store the callback
// and continue.
if ($default && $gateway['id'] == variable_get('uc_payment_' . $method . '_gateway', '')) {
$callback = $gateway[$method];
continue;
}
// If we want to use a specific gateway and this is it, store the callback.
if (!empty($selected) && $gateway['id'] == $selected) {
$callback = $gateway[$method];
}
}
// If we found a callback...
if ($callback !== FALSE) {
// Check to see if the function exists and process the payment.
if (function_exists($callback)) {
$result = $callback($order_id, $amount, $data);
}
else {
// Otherwise display an error message to administrators.
if (user_access('administer store')) {
drupal_set_message(t('An error has occurred with your payment gateway. The charge function could not be found.'));
}
$result['success'] = FALSE;
}
}
else {
// Otherwise store the info that was passed to us in the session and
// redirect to a form where we can choose a payment gateway.
$_SESSION['uc_payment_method'] = $method;
$_SESSION['uc_payment_order_id'] = $order_id;
$_SESSION['uc_payment_amount'] = $amount;
$_SESSION['uc_payment_data'] = serialize($data);
drupal_goto('admin/store/orders/' . $order_id . '/payments/select/' . $method);
}
}
// 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 failue 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'];
}
/**
* Enter a payment for an order.
*/
function uc_payment_enter($order_id, $method, $amount, $uid, $data, $comment) {
$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);
}
if (variable_get('uc_payment_logging', TRUE)) {
global $user;
$log_message = t('@method payment for @amount entered by @user.', array('@method' => $method_name, '@amount' => uc_currency_format($amount), '@user' => uc_get_initials($user->uid)));
uc_order_log_changes($order_id, array($log_message));
}
db_insert('uc_payment_receipts')
->fields(array(
'order_id' => $order_id,
'method' => $method_name,
'amount' => $amount,
'uid' => $uid,
'data' => $data,
'comment' => $comment,
'received' => REQUEST_TIME,
))
->execute();
$order = uc_order_load($order_id, TRUE);
$account = user_load($uid);
module_invoke_all('uc_payment_entered', $order, $method, $amount, $account, $data, $comment);
if (module_exists('rules')) {
rules_invoke_event('uc_payment_entered', $order, $account);
}
}
/**
* Delete a payment from the database.
*/
function uc_payment_delete($receipt_id) {
if (!is_numeric($receipt_id)) {
return FALSE;
}
if (variable_get('uc_payment_logging', TRUE)) {
global $user;
$payment = uc_payment_load($receipt_id);
$log_message = t('@method payment for @amount deleted by @user.', array('@method' => $payment->method, '@amount' => uc_currency_format($payment->amount), '@user' => uc_get_initials($user->uid)));
uc_order_log_changes($payment->order_id, array($log_message));
}
db_delete('uc_payment_receipts')
->condition('receipt_id', $receipt_id)
->execute();
}
/**
* Return 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;
}
/**
* Load 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;
}
/**
* Load an array of all the payments for an order.
*
* @param $order_id
* The order's id.
* @param $action
* Unused...
*
* @return
* Array of payment objects or FALSE if there are none.
*/
function uc_payment_load_payments($order_id, $action = NULL) {
$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;
}
/**
* Build a list of payment methods defined in the enabled modules.
*/
function _uc_payment_method_list($action = NULL) {
static $methods;
if (count($methods) > 0 && $action !== 'rebuild') {
return $methods;
}
$methods = module_invoke_all('uc_payment_method');
foreach ($methods as $i => $value) {
$methods[$i]['checkout'] = variable_get('uc_payment_method_' . $methods[$i]['id'] . '_checkout', $methods[$i]['checkout']);
$methods[$i]['weight'] = variable_get('uc_payment_method_' . $methods[$i]['id'] . '_weight', $methods[$i]['weight']);
}
usort($methods, 'uc_weight_sort');
return $methods;
}
/**
* Return 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();
foreach ($methods as $method) {
if ($method['id'] == $method_id) {
return isset($method[$key]) ? $method[$key] : NULL;
}
}
}
/**
* Build a list of payment gateways defined in the enabled modules.
*/
function _uc_payment_gateway_list($filter = NULL, $enabled_only = FALSE) {
$gateways = module_invoke_all('uc_payment_gateway');
foreach ($gateways as $i => $value) {
$gateways[$i]['enabled'] = variable_get('uc_pg_' . $gateways[$i]['id'] . '_enabled', TRUE);
if ($filter != NULL) {
if (!isset($gateways[$i][$filter]) || !function_exists($gateways[$i][$filter])) {
unset($gateways[$i]);
continue;
}
}
if ($enabled_only) {
if (!variable_get('uc_pg_' . $gateways[$i]['id'] . '_enabled', TRUE)) {
unset($gateways[$i]);
}
}
}
return $gateways;
}
/**
* Return 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) {
// Load all the payment gateways.
$gateways = _uc_payment_gateway_list();
// Loop through the array to find the matching gateway.
foreach ($gateways as $gateway) {
// If this is it, return the requested data.
if ($gateway['id'] == $gateway_id) {
return isset($gateway[$key]) ? $gateway[$key] : NULL;
}
}
}