'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 .= '' . ''; } } $output .= '' . '
' . filter_xss($line['title']) . ':' . theme('uc_price', array('price' => $line['amount'])) . '
' . 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; } } }