You are here

uc_payment.module in Ubercart 5

File

payment/uc_payment/uc_payment.module
View source
<?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.
 *
 * Development sponsored by the Ubercart project.  http://www.ubercart.org
 */
require_once 'uc_payment_checkout_pane.inc';
require_once 'uc_payment_order_pane.inc';
require_once 'uc_payment_workflow.inc';

/*******************************************************************************
 * Hook Functions (Drupal)
 ******************************************************************************/

/**
 * Implementation of hook_menu().
 */
function uc_payment_menu($may_cache) {
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/store/settings/payment',
      'title' => t('Payment settings'),
      'callback' => 'uc_payment_settings_overview',
      'access' => user_access('administer store'),
      'description' => t('Configure the payment settings.'),
    );
    $items[] = array(
      'path' => 'admin/store/settings/payment/overview',
      'title' => t('Overview'),
      'access' => user_access('administer store'),
      'description' => t('View the payment settings.'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -10,
    );
    $items[] = array(
      'path' => 'admin/store/settings/payment/edit',
      'title' => t('Edit'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'uc_payment_settings_form',
      ),
      'access' => user_access('administer store'),
      'description' => t('Edit the payment settings.'),
      'type' => MENU_LOCAL_TASK,
      'weight' => -5,
    );
    $items[] = array(
      'path' => 'admin/store/settings/payment/edit/basic',
      'title' => t('Payment settings'),
      'access' => user_access('administer store'),
      'description' => t('Edit the basic payment settings.'),
      'type' => MENU_DEFAULT_LOCAL_TASK,
      'weight' => -10,
    );
    $items[] = array(
      'path' => 'admin/store/settings/payment/edit/methods',
      'title' => t('Payment methods'),
      'access' => user_access('administer store'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'uc_payment_methods_form',
      ),
      'description' => t('Edit the payment method settings.'),
      'type' => MENU_LOCAL_TASK,
      'weight' => -5,
    );
    $items[] = array(
      'path' => 'admin/store/settings/payment/edit/gateways',
      'title' => t('Payment gateways'),
      'access' => user_access('administer store'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'uc_payment_gateways_form',
      ),
      'description' => t('Edit the payment gateway settings.'),
      'type' => MENU_LOCAL_TASK,
      'weight' => 0,
    );
    $items[] = array(
      'path' => 'cart/checkout/line_items',
      'title' => t('Return order totals'),
      'callback' => 'uc_payment_get_totals',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
    );
  }
  else {
    $items[] = array(
      'path' => 'cart/checkout/payment_details/' . arg(3),
      'title' => t('Payment details'),
      'description' => t('Add the payment details to the checkout pane.'),
      'callback' => 'uc_payment_get_details',
      'callback arguments' => array(
        arg(3),
      ),
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
    );
    if (is_numeric(arg(3))) {
      $items[] = array(
        'path' => 'admin/store/orders/' . arg(3) . '/payment_details/' . arg(5),
        'title' => t('Payment details'),
        'description' => t('Add the payment details to the order pane.'),
        'callback' => 'uc_payment_get_details',
        'callback arguments' => array(
          arg(5),
          'order',
        ),
        'access' => user_access('edit orders'),
        'type' => MENU_CALLBACK,
      );
      $items[] = array(
        'path' => 'admin/store/orders/' . arg(3) . '/payments/select/' . arg(6),
        'title' => t('Select payment gateway'),
        'callback' => 'uc_payment_gateway_select',
        'callback arguments' => array(
          arg(3),
          arg(6),
        ),
        'access' => user_access('view all orders'),
        'type' => MENU_CALLBACK,
      );
      if (variable_get('uc_payment_tracking', TRUE)) {
        $items[] = array(
          'path' => 'admin/store/orders/' . arg(3) . '/payments',
          'title' => t('Payments'),
          'callback' => 'drupal_get_form',
          'callback arguments' => array(
            'uc_payment_by_order_form',
            arg(3),
          ),
          'access' => user_access('view payments'),
          'weight' => 5,
          'type' => MENU_LOCAL_TASK,
        );
      }
      if (is_numeric(arg(5)) && arg(6) == 'delete' && variable_get('uc_payment_deleting', TRUE)) {
        $items[] = array(
          'path' => 'admin/store/orders/' . arg(3) . '/payments/' . arg(5) . '/delete',
          'title' => t('Delete payment?'),
          'description' => t('Delete payment?'),
          'callback' => 'drupal_get_form',
          'callback arguments' => array(
            'uc_payment_delete_confirm_form',
            arg(3),
            arg(5),
          ),
          'access' => user_access('delete payments'),
          'type' => MENU_CALLBACK,
        );
      }
    }
  }
  return $items;
}

/**
 * Implementation of hook_token_values().
 */
function uc_payment_token_values($type, $object = NULL) {
  switch ($type) {
    case 'order':
      $order = $object;
      $values['order-payment-method'] = _payment_method_data($order->payment_method, 'review');
      if (empty($values['order-payment-method'])) {
        $values['order-payment-method'] = _payment_method_data($order->payment_method, 'name');
      }
      $values['order-payment-balance'] = uc_currency_format(uc_payment_balance($order));
      break;
  }
  return $values;
}

/**
 * Implementation of hook_token_list(). (token.module)
 */
function uc_payment_token_list($type = 'all') {
  if ($type == 'order' || $type == 'ubercart' || $type == 'all') {
    $tokens['order']['order-payment-method'] = t('The payment method of the order.');
    $tokens['order']['order-payment-balance'] = t('The payment balance of the order');
  }
  return $tokens;
}

/**
 * Implementation of hook_perm().
 */
function uc_payment_perm() {
  return array(
    'view payments',
    'manual payments',
    'delete payments',
  );
}

/**
 * Implementation of hook_form_alter().
 */
function uc_payment_form_alter($form_id, &$form) {
  if ($form_id == 'uc_cart_checkout_form') {
    uc_add_js('misc/progress.js');
    uc_add_js(drupal_get_path('module', 'uc_payment') . '/uc_payment.js');
  }
}

/*******************************************************************************
 * Hook Functions (TAPIr)
 ******************************************************************************/

/**
 * Implementation of hook_table_settings().
 */
function uc_payment_table_settings() {
  $tables[] = array(
    'id' => 'uc_payments_table',
    'description' => t('The payments table on the order payments screen.'),
    'path' => 'admin/store/settings/tables',
    'access' => 'view all orders',
    'preview' => FALSE,
  );
  return $tables;
}

/*******************************************************************************
 * Hook Functions (Ubercart)
 ******************************************************************************/

/**
 * Implementation of hook_order().
 */
function uc_payment_order($op, &$arg1) {
  switch ($op) {
    case 'submit':
      $func = _payment_method_data($arg1->payment_method, 'callback');
      if (function_exists($func)) {
        return $func('order-submit', $arg1);
      }
      break;
    case 'load':
      $func = _payment_method_data($arg1->payment_method, 'callback');
      if (function_exists($func)) {
        $func('order-load', $arg1);
      }
      break;
    case 'save':
      $func = _payment_method_data($arg1->payment_method, 'callback');
      if (function_exists($func)) {
        $func('order-save', $arg1);
      }
      break;
    case 'can_delete':
      if (uc_payment_load_payments($arg1->order_id) !== FALSE) {
        return FALSE;
      }
      break;
    case 'delete':
      db_query("DELETE FROM {uc_payment_receipts} WHERE order_id = %d", $arg1->order_id);

      // Call each payment method to delete method specific data from the database.
      $methods = _payment_method_list();
      foreach ($methods as $method) {
        $func = $method['callback'];
        if (function_exists($func)) {
          $func('order-delete', $arg1);
        }
      }
      break;
  }
}

/**
 * Implementation of hook_checkout_pane().
 */
function uc_payment_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;
}

/**
 * Implementation of hook_order_pane().
 */
function uc_payment_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;
}

/**
 * Implementation of hook_order_state().
 */
function uc_payment_order_state() {
  $states[] = array(
    'id' => 'payment_received',
    'title' => t('Payment received'),
    'weight' => 10,
    'scope' => 'general',
  );
  return $states;
}

/*******************************************************************************
 * Callback Functions, Forms, and Tables
 ******************************************************************************/

/**
 * Display the payment settings overview.
 */
function uc_payment_settings_overview() {
  $sections[] = array(
    'edit' => 'admin/store/settings/payment/edit',
    'title' => t('Payment settings'),
    'items' => array(
      t('Payment tracking is !status.', array(
        '!status' => variable_get('uc_payment_tracking', TRUE) ? t('enabled') : t('disabled'),
      )),
      t('Payments !status be deleted by approved users.', array(
        '!status' => variable_get('uc_payment_deleting', TRUE) ? t('may') : t('may not'),
      )),
      t('Payments are !status in the order logs.', array(
        '!status' => variable_get('uc_payment_logging', TRUE) ? t('tracked') : t('not tracked'),
      )),
      t('Default payment details message:<br />%message', array(
        '%message' => variable_get('uc_default_payment_msg', t('Continue with checkout to complete payment.')),
      )),
    ),
  );
  $methods = _payment_method_list();
  foreach ($methods as $method) {
    $items[] = t('!title is !status for checkout.', array(
      '!title' => $method['name'],
      '!status' => $method['checkout'] ? t('enabled') : t('disabled'),
    ));
  }
  $sections[] = array(
    'edit' => 'admin/store/settings/payment/edit/methods',
    'title' => t('Payment methods'),
    'items' => $items,
  );
  $items = array();
  $gateways = _payment_gateway_list();
  foreach ($gateways as $gateway) {
    $items[] = t('!title is !status.', array(
      '!title' => $gateway['title'],
      '!status' => $gateway['enabled'] ? t('enabled') : t('disabled'),
    ));
  }
  $sections[] = array(
    'edit' => 'admin/store/settings/payment/edit/gateways',
    'title' => t('Payment gateways'),
    'items' => $items,
  );
  $output = theme('uc_settings_overview', $sections);
  return $output;
}
function uc_payment_settings_form() {
  $form['uc_payment_tracking'] = array(
    '#type' => 'checkbox',
    '#title' => t('Enable payment tracking.'),
    '#default_value' => variable_get('uc_payment_tracking', TRUE),
  );
  $form['uc_payment_deleting'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow payments to be deleted by users with permission.'),
    '#default_value' => variable_get('uc_payment_deleting', TRUE),
  );
  $form['uc_payment_logging'] = array(
    '#type' => 'checkbox',
    '#title' => t('Log payments entered and deleted to order log.'),
    '#default_value' => variable_get('uc_payment_logging', TRUE),
  );
  $form['uc_default_payment_msg'] = array(
    '#type' => 'textfield',
    '#title' => t('Default payment details message'),
    '#description' => t('Message displayed when a payment method does not display any further details.'),
    '#default_value' => variable_get('uc_default_payment_msg', t('Continue with checkout to complete payment.')),
  );
  return system_settings_form($form);
}
function uc_payment_methods_form() {
  $methods = _payment_method_list();
  $form['methods_info'] = array(
    '#value' => '<div><strong>' . t('Payment methods') . '</strong><br />' . t('The settings forms below are for the payment methods defined by enabled modules. Click a name to expand its options and adjust the settings accordingly. Methods are listed in order of appearance on the checkout screen, determined by the weight setting (current value shown in parentheses).') . '</div><br />',
  );
  $form['pmtable'] = array(
    '#theme' => 'uc_payment_method_table',
  );
  if (is_array($methods) && count($methods) > 0) {
    foreach ($methods as $method) {
      $form['pmtable'][$method['id']]['uc_payment_method_' . $method['id'] . '_checkout'] = array(
        '#type' => 'checkbox',
        '#default_value' => variable_get('uc_payment_method_' . $method['id'] . '_checkout', $method['checkout']),
      );
      $form['pmtable'][$method['id']]['name'] = array(
        '#value' => $method['name'],
      );
      $form['pmtable'][$method['id']]['uc_payment_method_' . $method['id'] . '_weight'] = array(
        '#type' => 'weight',
        '#default_value' => variable_get('uc_payment_method_' . $method['id'] . '_weight', $method['weight']),
      );
      if ($method['no_gateway'] === TRUE) {
        $form['pmtable'][$method['id']]['uc_payment_' . $method['id'] . '_gateway'] = array(
          '#value' => '-',
        );
      }
      else {
        $gateways = _payment_gateway_list($method['id'], TRUE);
        $options = array();
        $default = FALSE;
        if (is_array($gateways)) {
          foreach ($gateways as $gateway) {
            if (!$default) {
              $default = $gateway['id'];
            }
            $options[$gateway['id']] = $gateway['title'];
          }
        }
        if (!$default) {
          $options = array(
            'none' => t('None available.'),
          );
        }
        $form['pmtable'][$method['id']]['uc_payment_' . $method['id'] . '_gateway'] = array(
          '#type' => 'select',
          '#options' => $options,
          '#default_value' => variable_get('uc_payment_' . $method['id'] . '_gateway', 'none'),
        );
      }
      $null = NULL;
      $method_settings = $method['callback']('settings', $null);
      if (is_array($method_settings)) {
        $form['method_' . $method['id']] = array(
          '#type' => 'fieldset',
          '#title' => t('!method settings', array(
            '!method' => $method['name'],
            '!weight' => $method['weight'],
          )),
          '#collapsible' => TRUE,
          '#collapsed' => TRUE,
        );
        $form['method_' . $method['id']] = array_merge($form['method_' . $method['id']], $method_settings);
      }
    }
  }
  return system_settings_form($form);
}
function theme_uc_payment_method_table($form) {
  $header = array(
    t('Enabled'),
    t('Payment method'),
    t('Weight'),
    t('Default gateway'),
  );
  foreach (element_children($form) as $method) {
    $rows[] = array(
      array(
        'data' => drupal_render($form[$method]['uc_payment_method_' . $method . '_checkout']),
        'align' => 'center',
      ),
      drupal_render($form[$method]['name']),
      drupal_render($form[$method]['uc_payment_method_' . $method . '_weight']),
      drupal_render($form[$method]['uc_payment_' . $method . '_gateway']),
    );
  }
  if (empty($rows)) {
    $rows[] = array(
      array(
        'data' => t('No payment methods founds.'),
        'colspan' => 5,
      ),
    );
  }
  return theme('table', $header, $rows);
}
function uc_payment_gateways_form() {
  $gateways = _payment_gateway_list();
  $methods = _payment_method_list();
  if (is_array($gateways) && count($gateways) > 0) {
    $form['gateways_info'] = array(
      '#value' => '<div><strong>' . t('Payment gateways') . '</strong><br />' . t('Payment gateways are web services that allow you to process various types of payments remotely.  The settings forms below are for the payment gateways you have installed.  Click a name to expand its options and adjust the settings accordingly.') . '</div>',
    );
    foreach ($gateways as $gateway) {
      $form['gateways'][$gateway['id']] = array(
        '#type' => 'fieldset',
        '#title' => t('@gateway_name settings', array(
          '@gateway_name' => $gateway['title'],
        )),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      );
      $supported_methods = array();
      foreach ($methods as $method) {
        if (isset($gateway[$method['id']]) && function_exists($gateway[$method['id']])) {
          $supported_methods[] = $method['name'];
        }
      }
      $form['gateways'][$gateway['id']]['supported_methods'] = array(
        '#value' => '<div>' . t('This gateway supports the following payment methods:') . '<br />' . implode(',', $supported_methods) . '</div>',
        '#weight' => -10,
      );
      $form['gateways'][$gateway['id']]['uc_pg_' . $gateway['id'] . '_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable this payment gateway for use.'),
        '#default_value' => variable_get('uc_pg_' . $gateway['id'] . '_enabled', TRUE),
        '#weight' => -7,
      );

      // Find any additional settings defined in the payment gateway callback.
      if (function_exists($gateway['settings'])) {
        $gateway_settings = $gateway['settings']();
        if (is_array($gateway_settings)) {
          $form['gateways'][$gateway['id']] = array_merge($form['gateways'][$gateway['id']], $gateway_settings);
        }
      }
    }
  }
  return system_settings_form($form);
}
function uc_payment_get_details($method_id, $view = 'cart') {
  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;
    }
  }
  elseif ($view == 'order') {
    $order = uc_order_load(arg(3));
  }
  $func = _payment_method_data($method_id, 'callback');
  if (function_exists($func)) {
    $output = $func($view . '-details', $order);
  }
  print $output;
  exit;
}
function uc_payment_get_totals() {
  if (is_array($_POST)) {
    foreach ($_POST as $key => $value) {
      $totals[$key] = explode(';', $value);
    }
  }
  if (is_array($totals) && count($totals) > 0) {
    usort($totals, '_total_sort');
    $output = t('Order total preview:') . ' <span id="order-total-throbber"></span><table>';
    $grand_total = 0;
    foreach ($totals as $line) {
      if (!empty($line[2])) {
        $output .= '<tr><td align="right"><b>' . $line[2] . ':</b></td>' . '<td align="right">' . uc_currency_format($line[1]) . '</td></tr>';
        if ($line[3]) {
          $grand_total += round($line[1], 2);
        }
      }
    }
    $output .= '<tr><td align="right"><b>' . t('Order total:') . '</b></td>' . '<td align="right">' . uc_currency_format($grand_total) . '</td></tr></table>';
  }
  print $output;
  exit;
}
function _total_sort($a, $b) {
  if ($a[0] == $b[0]) {
    return 0;
  }
  return $a[0] < $b[0] ? -1 : 1;
}

// Displays a list of payments attached to an order.
function uc_payment_by_order_form($order_id) {
  $order = uc_order_load($order_id);
  if ($order === FALSE) {
    drupal_set_message(t('Order %id does not exist.', array(
      '%id' => $order_id,
    )));
    drupal_goto('admin/store/orders');
  }
  $total = $order->order_total;
  $payments = uc_payment_load_payments($order_id);
  $form['order_total'] = array(
    '#value' => uc_currency_format($total),
  );
  $form['payments'] = array(
    '#tree' => TRUE,
  );
  if ($payments !== FALSE) {
    foreach ($payments as $payment) {
      $form['payments'][$payment->receipt_id]['received'] = array(
        '#value' => format_date($payment->received, 'custom', variable_get('uc_date_format_default', 'm/d/Y') . '<b\\r>H:i:s'),
      );
      $form['payments'][$payment->receipt_id]['user'] = array(
        '#value' => uc_get_initials($payment->uid),
      );
      $form['payments'][$payment->receipt_id]['method'] = array(
        '#value' => $payment->method == '' ? t('Unknown') : $payment->method,
      );
      $form['payments'][$payment->receipt_id]['amount'] = array(
        '#value' => uc_currency_format($payment->amount),
      );
      $total -= $payment->amount;
      $form['payments'][$payment->receipt_id]['balance'] = array(
        '#value' => uc_currency_format($total),
      );
      $form['payments'][$payment->receipt_id]['comment'] = array(
        '#value' => $payment->comment == '' ? '-' : filter_xss_admin($payment->comment),
      );
      if (variable_get('uc_payment_deleting', TRUE) && user_access('delete payments')) {
        $action_value = l(t('Delete'), 'admin/store/orders/' . $order_id . '/payments/' . $payment->receipt_id . '/delete');
      }
      else {
        $action_value = '-';
      }
      $form['payments'][$payment->receipt_id]['action'] = array(
        '#value' => $action_value,
      );
    }
  }
  $form['balance'] = array(
    '#value' => uc_currency_format($total),
  );
  $form['order_id'] = array(
    '#type' => 'hidden',
    '#value' => $order_id,
  );
  if (user_access('manual payments')) {
    $form['payments']['new']['received'] = array(
      '#value' => '-',
    );
    $form['payments']['new']['user'] = array(
      '#value' => '-',
    );
    $methods = _payment_method_list();
    foreach ($methods as $method) {
      $options[$method['id']] = $method['name'];
    }
    $form['payments']['new']['method'] = array(
      '#type' => 'select',
      '#options' => $options,
    );
    $form['payments']['new']['amount'] = array(
      '#type' => 'textfield',
      '#size' => 6,
    );
    $form['payments']['new']['balance'] = array(
      '#value' => '-',
    );
    $form['payments']['new']['comment'] = array(
      '#type' => 'textfield',
      '#size' => 32,
      '#maxlength' => 256,
    );
    $form['payments']['new']['action'] = array(
      '#type' => 'submit',
      '#value' => t('Enter'),
    );
  }
  return $form;
}
function uc_payment_by_order_form_validate($form_id, $form_values) {
  if (!is_numeric($form_values['payments']['new']['amount'])) {
    form_set_error('payments][new][amount', t('You must enter a number for the amount.'));
  }
  return TRUE;
}
function uc_payment_by_order_form_submit($form_id, $form_values) {
  global $user;
  $payment = $form_values['payments']['new'];
  uc_payment_enter($form_values['order_id'], $payment['method'], $payment['amount'], $user->uid, '', $payment['comment']);
  drupal_set_message(t('Payment entered.'));
}
function theme_uc_payment_by_order_form($form) {
  $output = '<p><strong>' . t('Order total:') . '</strong> ' . drupal_render($form['order_total']) . '<br /><strong>' . t('Current balance:') . '</strong> ' . drupal_render($form['balance']) . '</p>';
  $output .= '<p>' . tapir_get_table('uc_payments_table', $form) . '</p>' . '<p>' . drupal_render($form['form_id']) . drupal_render($form['form_token']) . '</p>';
  return $output;
}
function uc_payments_table($op, $form) {
  switch ($op) {
    case 'fields':
      $fields[] = array(
        'name' => 'received',
        'title' => t('Received'),
        'weight' => 0,
        'enabled' => TRUE,
      );
      $fields[] = array(
        'name' => 'user',
        'title' => t('User'),
        'weight' => 1,
        'enabled' => TRUE,
      );
      $fields[] = array(
        'name' => 'method',
        'title' => t('Method'),
        'weight' => 2,
        'enabled' => TRUE,
      );
      $fields[] = array(
        'name' => 'amount',
        'title' => t('Amount'),
        'weight' => 3,
        'enabled' => TRUE,
      );
      $fields[] = array(
        'name' => 'balance',
        'title' => t('Balance'),
        'weight' => 4,
        'enabled' => TRUE,
      );
      $fields[] = array(
        'name' => 'comment',
        'title' => t('Comment'),
        'weight' => 5,
        'enabled' => TRUE,
      );
      $fields[] = array(
        'name' => 'action',
        'title' => t('Action'),
        'weight' => 6,
        'enabled' => TRUE,
      );
      return $fields;
    case 'data':
      foreach (element_children($form['payments']) as $i) {
        $data['#attributes'][] = array(
          'valign' => 'top',
        );
        $data['received'][] = drupal_render($form['payments'][$i]['received']);
        $data['user'][] = drupal_render($form['payments'][$i]['user']);
        $data['method'][] = drupal_render($form['payments'][$i]['method']);
        $data['amount'][] = drupal_render($form['payments'][$i]['amount']);
        $data['balance'][] = drupal_render($form['payments'][$i]['balance']);
        $data['comment'][] = drupal_render($form['payments'][$i]['comment']);
        $data['action'][] = drupal_render($form['payments'][$i]['action']);
      }
      return $data;
  }
}

// Confirmation form to delete a payment from an order.
function uc_payment_delete_confirm_form($order_id, $receipt_id) {

  // Attempt to load the payment.
  $payment = uc_payment_load($receipt_id);

  // Get outta here if the payment doesn't exist.
  if ($payment->order_id != $order_id) {
    drupal_set_message(t('An error loading the payment information occurred.'));
    drupal_goto('admin/store/orders/' . $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_id,
  );
  $form['receipt_id'] = array(
    '#type' => 'value',
    '#value' => $receipt_id,
  );
  return confirm_form($form, t('Are you sure you want to delete this payment?'), 'admin/store/orders/' . $order_id . '/payments', $desc, t('Delete'));
}
function uc_payment_delete_confirm_form_submit($form_id, $form_values) {
  uc_payment_delete($form_values['receipt_id']);
  drupal_set_message(t('Payment deleted.'));
  return 'admin/store/orders/' . $form_values['order_id'] . '/payments';
}

/**
 * Select a payment gateway to process a payment when multiple gateways
 * exist for a given payment method.
 */
function uc_payment_gateway_select($url_order_id) {
  $gateways = _payment_gateway_list($_SESSION['uc_payment_method'], TRUE);
  foreach ($gateways as $gateway) {
    $options[$gateway['id']] = $gateway['title'];
  }
  $output = t('Please choose a payment gateway to use for that payment.');
  $output .= drupal_get_form('uc_payment_gateway_select_form', $options, $_SESSION['uc_payment_method'], $_SESSION['uc_payment_order_id'], $_SESSION['uc_payment_amount'], $_SESSION['uc_payment_data']);
  return $output;
}
function uc_payment_gateway_select_form($options, $method, $order_id, $amount, $data) {
  $form['method'] = array(
    '#type' => 'hidden',
    '#value' => $method,
  );
  $form['order_id'] = array(
    '#type' => 'hidden',
    '#value' => $order_id,
  );
  $form['amount'] = array(
    '#type' => 'hidden',
    '#value' => $amount,
  );
  $form['p_data'] = array(
    '#type' => 'hidden',
    '#value' => $data,
  );
  $form['p_selected'] = array(
    '#type' => 'select',
    '#title' => t('Use gateway'),
    '#options' => $options,
    '#default_value' => variable_get('uc_payment_' . $method . '_gateway', ''),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Process'),
  );
  return $form;
}
function uc_payment_gateway_select_form_submit($form_id, $form_values) {
  unset($_SESSION['uc_payment_method']);
  unset($_SESSION['uc_payment_order_id']);
  unset($_SESSION['uc_payment_amount']);
  unset($_SESSION['uc_payment_data']);
  uc_payment_process($form_values['method'], $form_values['order_id'], $form_values['amount'], unserialize($form_values['p_data']), FALSE, $form_values['p_selected']);
  drupal_goto('admin/store/orders/' . $form_values['order_id']);
}

/*******************************************************************************
 * 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($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 = _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' => _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 ($result['log_payment'] !== FALSE) {
      uc_payment_enter($order_id, $method, $amount, empty($result['uid']) ? 0 : $result['uid'], $result['data'], $result['comment']);
    }
  }
  else {

    // Otherwise display the failue message in the logs.
    watchdog('uc_payment', t('Payment failed: @message', array(
      '@message' => $result['message'],
    )), WATCHDOG_WARNING);
  }

  // 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 = _payment_method_data($method, 'review');
  if (empty($method_name)) {
    $method_name = _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_query("INSERT INTO {uc_payment_receipts} (receipt_id, order_id, method, amount, uid, data, comment, received) VALUES (%d, %d, '%s', %f, %d, '%s', '%s', %d)", db_next_id('{uc_payment_receipts}_receipt_id'), $order_id, $method_name, $amount, $uid, $data, $comment, time());
  if (module_exists('workflow_ng')) {
    workflow_ng_invoke_event('payment_entered', uc_order_load($order_id));
  }
}

/**
 * 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_query("DELETE FROM {uc_payment_receipts} WHERE receipt_id = %d", $receipt_id);
}

/**
 * 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;
  }
  $result = db_query("SELECT * FROM {uc_payment_receipts} WHERE receipt_id = %d ", $receipt_id);
  $payment = db_fetch_object($result);
  return $payment;
}

/**
 * Load an array of all the payments for order $order_id.
 */
function uc_payment_load_payments($order_id, $action = NULL) {
  $payments = array();
  $result = db_query("SELECT * FROM {uc_payment_receipts} WHERE order_id = %d " . "ORDER BY received ASC", $order_id);
  while ($payment = db_fetch_object($result)) {
    $payments[] = $payment;
  }
  if (count($payments) == 0) {
    $payments = FALSE;
  }
  return $payments;
}

/**
 * Build a list of payment methods defined in the enabled modules.
 */
function _payment_method_list($action = NULL) {
  static $methods;
  if (count($methods) > 0 && $action !== 'rebuild') {
    return $methods;
  }
  $methods = module_invoke_all('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 _payment_method_data($method_id, $key) {
  $methods = _payment_method_list();
  foreach ($methods as $method) {
    if ($method['id'] == $method_id) {
      return $method[$key];
    }
  }
}

/**
 * Build a list of payment gateways defined in the enabled modules.
 */
function _payment_gateway_list($filter = NULL, $enabled_only = FALSE) {
  $gateways = module_invoke_all('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]);
      }
    }
    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 _payment_gateway_data($gateway_id, $key) {

  // Load all the payment gateways.
  $gateways = _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 $gateway[$key];
    }
  }
}

Functions

Namesort descending Description
theme_uc_payment_by_order_form
theme_uc_payment_method_table
uc_payments_table
uc_payment_balance Return the balance of payments on an order.
uc_payment_by_order_form
uc_payment_by_order_form_submit
uc_payment_by_order_form_validate
uc_payment_checkout_pane Implementation of hook_checkout_pane().
uc_payment_delete Delete a payment from the database.
uc_payment_delete_confirm_form
uc_payment_delete_confirm_form_submit
uc_payment_enter Enter a payment for an order.
uc_payment_form_alter Implementation of hook_form_alter().
uc_payment_gateways_form
uc_payment_gateway_select Select a payment gateway to process a payment when multiple gateways exist for a given payment method.
uc_payment_gateway_select_form
uc_payment_gateway_select_form_submit
uc_payment_get_details
uc_payment_get_totals
uc_payment_load Load a single payment from the database by receipt_id.
uc_payment_load_payments Load an array of all the payments for order $order_id.
uc_payment_menu Implementation of hook_menu().
uc_payment_methods_form
uc_payment_order Implementation of hook_order().
uc_payment_order_pane Implementation of hook_order_pane().
uc_payment_order_state Implementation of hook_order_state().
uc_payment_perm Implementation of hook_perm().
uc_payment_process Process a payment through an enabled payment gateway.
uc_payment_settings_form
uc_payment_settings_overview Display the payment settings overview.
uc_payment_table_settings Implementation of hook_table_settings().
uc_payment_token_list Implementation of hook_token_list(). (token.module)
uc_payment_token_values Implementation of hook_token_values().
_payment_gateway_data Return data from a payment gateway by gateway ID and the array key.
_payment_gateway_list Build a list of payment gateways defined in the enabled modules.
_payment_method_data Return data from a payment method by method ID and the array key.
_payment_method_list Build a list of payment methods defined in the enabled modules.
_total_sort