You are here

pay.module in Pay 7

Same filename and directory in other branches
  1. 6 pay.module

Pay module allows for accepting payments using pluggable payment backends.

File

pay.module
View source
<?php

/**
 * @file
 * Pay module allows for accepting payments using pluggable payment backends.
 */

/**
 * Implements hook_init().
 */
function pay_init() {
  $path = drupal_get_path('module', 'pay');
  if (module_exists('trigger')) {
    module_load_include('inc', 'pay', 'includes/pay.trigger');
  }
  if (module_exists('token')) {
    module_load_include('inc', 'pay', 'includes/pay.token');
  }
  module_load_include('inc', 'pay', 'includes/pay.action');
}

/**
 * Implements hook_menu().
 */
function pay_menu() {
  module_load_include('inc', 'pay', 'includes/pay.menu');
  return pay_menu_menu();
}

/**
 * Implements hook_permission().
 */
function pay_permission() {

  // Permissions based on form types and global settings.
  $permissions = array(
    'view reports for any payment form' => array(
      'title' => t('view reports for any payment form'),
      'description' => t('View reports for any payment form'),
    ),
    'administer pay' => array(
      'title' => t('administer pay'),
      'description' => t('Administer pay module'),
    ),
    'administer payments for any form' => array(
      'title' => t('administer payments for any form'),
      'description' => t('Administer payments for any pay module form'),
    ),
    'make payments on any form' => array(
      'title' => t('make payments on any form'),
      'description' => t('Make payments on any pay module form'),
    ),
  );
  foreach (pay_handlers('pay_form') as $name => $info) {
    $permissions['administer payments for ' . $name . ' forms'] = array(
      'title' => t('administer payments for ' . $name . ' form'),
      'description' => t('Administer payments for ' . $name . ' pay module form'),
    );
    $permissions['make payments on ' . $name . ' forms'] = array(
      'title' => t('administer payments for ' . $name . ' form'),
      'description' => t('Administer payments for ' . $name . ' pay module form'),
    );
    $permissions['view reports for ' . $name . ' forms'] = array(
      'title' => t('view reports for ' . $name . ' payment form'),
      'description' => t('View reports for ' . $name . ' payment form'),
    );
  }
  return $permissions;
}

/**
 * Implements hook_theme().
 */
function pay_theme() {
  module_load_include('inc', 'pay', 'theme/pay.theme');
  return pay_theme_theme();
}

/**
 * Implements hook_user_categories().
 */
function pay_user_categories() {

  // Return only a modes 'category' entry - the real work happens in the
  // page callback for payment settings.  See also hook_menu.
  return array(
    array(
      'name' => 'pay',
      'title' => 'Payments',
      'weight' => 10,
    ),
  );
}

/**
 * Implements hook_user_cancel().
 */
function pay_user_cancel($edit, $account, $method) {

  // Deactivate any payment forms this user may have created.
  db_update('pay_form')
    ->fields(array(
    'status' => 0,
    'uid' => 0,
  ))
    ->condition('uid', $account->uid)
    ->execute();

  // Remove reference to this user's uid in transaction history.
  db_update('pay_transaction')
    ->fields(array(
    'uid' => 0,
  ))
    ->condition('uid', $account->uid)
    ->execute();
  db_update('pay_activity')
    ->fields(array(
    'uid' => 0,
  ))
    ->condition('uid', $account->uid)
    ->execute();
}

/**
 * An access callback for access to user-specific Payment settings form.
 */
function pay_user_settings_access($account) {

  // Permit access if any module returns TRUE in hook_pay_user_settings_access()
  foreach (module_implements('pay_user_settings_access') as $module) {
    $func = $module . '_pay_user_settings_access';
    if ($func($account)) {
      return TRUE;
    }
  }

  // Return FALSE by default, thus hiding the 'Payment settings' form.
  return FALSE;
}

/**
 * Form builder; Present the form to edit a user's payment settings.
 *
 * @ingroup forms
 */
function pay_user_settings_page($account, $category = 'default') {
  drupal_set_title($account->name);
  return drupal_get_form('pay_user_settings_form', $account, $category);
}

/**
 * A form callback for a user's 'Payment settings' page.
 */
function pay_user_settings_form($form, &$form_state, $account, $category = 'default') {
  $form = array();

  // Rely on whatever the underlying hooks might return.
  foreach (module_implements('pay_user_settings_form') as $module) {
    $func = $module . '_pay_user_settings_form';
    $func($form, $form_state, $account);
  }
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}

/**
 * Implements hook_views_api().
 */
function pay_views_api() {
  return array(
    'api' => 2,
    'path' => drupal_get_path('module', 'pay') . '/includes/views',
  );
}

/**
 * API Function: All available payment handlers.
 */
function pay_handlers($type, $handler_name = NULL, $refresh = FALSE) {
  static $handlers = array();
  if ($refresh || !isset($handlers[$type])) {
    module_load_include('inc', 'pay', 'includes/pay.handlers');
    $handlers[$type] = module_invoke_all($type . '_handler_info');
    foreach ($handlers[$type] as $name => $info) {
      if (!isset($info['module'])) {
        $handlers[$type][$name]['module'] = $name;
      }
      if (!isset($info['handler'])) {
        $handlers[$type][$name]['handler'] = $name;
      }
    }
  }
  if ($handler_name) {
    return $handlers[$type][$handler_name];
  }
  return $handlers[$type];
}

/**
 * API Function: Include a handler file for a payment object.
 */
function pay_load_handler($type, $name) {
  static $cache = array();
  if (!isset($cache[$type])) {

    // Base classes for handlers.
    module_load_include('inc', 'pay', 'includes/handlers/pay');
    module_load_include('inc', 'pay', 'includes/handlers/' . $type);
    $cache[$type] = array();
  }

  // This is a pay primitive class, so we're done.
  if ($type == $name) {
    return TRUE;
  }

  // Already loaded.
  if (isset($cache[$type][$name])) {
    return $cache[$type][$name];
  }
  if ($name && ($handler = pay_handlers($type, $name))) {

    // Ensure the parent is loaded.
    if (isset($handler['parent'])) {
      pay_load_handler($type, $handler['parent']);
    }

    // Respect the 'path' element that may have been specified.
    $file = isset($handler['path']) ? $handler['path'] . '/' : '';
    $file .= $name . '.inc';

    // Require the file, if it exists.
    if ($cache[$type][$name] = is_file($file)) {
      require_once DRUPAL_ROOT . '/' . $file;
    }
    return $cache[$type][$name];
  }
}

/**
 * API Function: Load a payment class.
 *
 * This function was renamed in D7 as to not collide with hook_load().
 */
function pay_load_object($type, $values = NULL) {
  if (is_scalar($values)) {
    if (is_numeric($values)) {
      if ($type == 'pay_form') {
        $key = 'pfid';
      }
      if ($type == 'pay_method') {
        $key = 'pmid';
      }
      if ($type == 'pay_item') {
        $key = 'piid';
      }
      if ($type == 'pay_transaction') {
        $key = 'pxid';
      }
      if ($type == 'pay_activity') {
        $key = 'paid';
      }
      $result = db_select($type, 't')
        ->fields('t')
        ->condition($key, $values)
        ->execute();
      if ($values = $result
        ->fetchObject()) {
        $handler = isset($values->handler) ? $values->handler : $type;
      }
      else {
        return FALSE;
      }
    }
    else {

      // It's just the name of a handler. Load it with defaults.
      $handler = $values;
      $values = NULL;
    }
  }
  else {
    $values = (object) $values;
    if (isset($values->handler)) {
      $handler = $values->handler;
    }
    elseif (isset($values->pmid)) {
      $handler_values = pay_load_object($type, $values->pmid);
      $handler = get_class($handler_values);
      $values = array_merge((array) $handler_values, (array) $values);
    }
    else {

      // Allow return of a generic object of the type requested.
      $handler = $type;
    }
  }
  if (pay_load_handler($type, $handler)) {
    return new $handler($values);
  }
}

/**
 * API Function: Load a payment form object.
 */
function pay_form_load($values = NULL) {
  return pay_load_object('pay_form', $values);
}

/**
 * API Function: Load a payment method object.
 */
function pay_method_load($values = NULL) {
  return pay_load_object('pay_method', $values);
}

/**
 * API Function: Load a payment transaction object.
 */
function pay_transaction_load($values = NULL) {
  return pay_load_object('pay_transaction', $values);
}

/**
 * API Function: Load a payment item object.
 */
function pay_item_load($values = NULL) {
  return pay_load_object('pay_item', $values);
}

/**
 * API Function: Load a payment activity object.
 */
function pay_activity_load($values = NULL) {
  return pay_load_object('pay_activity', $values);
}

/**
 * A simple form any type of pay element.
 * If you want to build a module with a standalone payment form, you would
 * do so by passing this function to the drupal_get_form page handler in your
 * hook_menu() funcion.
 *
 * Alternatively, you can manually add payment form capabilities by including
 * the code from this function in your form builder or form_alter code.
 *
 * TODO Rename this function as to not collide with hook_form().
 */
function pay_form($form, &$form_state, $pay, $type = NULL, $form_type = 'default') {
  if ($type) {
    $pay = pay_load_object($type, $pay);
  }

  // Add a "build mode" to $form_state so that the form handlers can render
  // forms differently based on user-defined context.
  $form_state['pay_form_type'] = $form_type;

  // Allow this handler to alter in all of its form fields. This will also
  // add the appropriate validate and submit callbacks for the Payment API.
  $pay
    ->form($form, $form_state);

  // Add a submit button, if we think it's necessary.
  if (!isset($form['submit']) && !isset($form[$pay
    ->handler()]['submit'])) {
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Submit payment'),
    );
  }
  return $form;
}

/**
 * A FAPI after_build handler for any type of pay form.
 */
function pay_after_build($form, &$form_state) {

  // Ensure that the pay_submit handler is added to the form after the others.
  $form['#validate'][] = 'pay_validate';
  $form['#submit'][] = 'pay_submit';
  return $form;
}

/**
 * Implements hook_form_alter().
 * Pass the form to any applicable pay handlers in case they have some input.
 */
function pay_form_alter(&$form, &$form_state, $form_id) {
  pay_form_callback('alter', $form, $form_state);
}

/**
 * A FAPI validate handler for any type of pay form.
 */
function pay_validate($form, &$form_state) {
  pay_form_callback('validate', $form, $form_state);
}

/**
 * A FAPI submit handler for any type of pay form.
 */
function pay_submit($form, &$form_state) {
  pay_form_callback('submit', $form, $form_state);
}

/**
 * A helper function for FAPI validate/submit callbacks.
 * Locates any pay elements in a form and calls thier handler code.
 */
function pay_form_callback($callback, &$form, &$form_state) {
  if (isset($form['#pay'])) {
    foreach ($form['#pay'] as $key => $item) {
      if ($pay = pay_load_object($item['type'], $item)) {
        $func = isset($item['form']) ? $item['form'] : 'form';
        $func .= '_' . $callback;
        if (method_exists($pay, $func)) {
          $pay
            ->{$func}($form, $form_state);
        }
        $form_state['pay'][$key] = $pay;
      }
    }
  }
}

/**
 * A helper function to be used as a #pre_render callback: Sets an element to
 * "required" for rendering.  The calling code should handle validation
 * responsibly.
 */
function pay_element_set_required($element) {
  $element['#required'] = TRUE;
  return $element;
}

/**
 * List of meaningful ways in which a payment form can appear.
 */
function pay_form_displays() {
  static $displays = array();
  if (!$displays) {
    $displays['pay_form_default'] = array(
      'title' => t('Default display of entire form'),
    );
    $displays['pay_form_amount'] = array(
      'title' => t('Amount only, with link to payment form'),
    );
    $displays['pay_form_link'] = array(
      'title' => t('Link to payment form'),
    );
    drupal_alter('pay_form_displays', $displays);
  }
  return $displays;
}

/**
 * Name/value List of meaningful ways in which a payment form can appear.
 */
function pay_form_displays_list() {
  $list = array();
  foreach (pay_form_displays($handler) as $key => $info) {
    $list[$key] = $info['title'];
  }
  return $list;
}

/**
 * List available payment forms.
 *
 * Renamed in D7 to avoid conflict with hook_forms().
 */
function pay_forms_list($handler = NULL, $embeddable = NULL, $status = 1) {
  $query = db_select('pay_form', 'pf')
    ->fields('pf');
  if (!is_null($handler)) {
    $query
      ->condition('handler', $handler);
  }
  if (!is_null($status)) {
    $query
      ->condition('status', $status);
  }
  if (!is_null($embeddable)) {
    $query
      ->condition('embeddable', $embeddable);
  }
  $query
    ->orderBy('title');
  $result = $query
    ->execute();
  $forms = array();
  while ($row = $result
    ->fetchObject()) {
    if ($pay_form = pay_form_load($row)) {
      $forms[$row->pfid] = $pay_form;
    }
  }
  return $forms;
}

/**
 * Helper function to list all payment methods available.
 */
function pay_method_list() {
  $list = array();
  $res = db_query("SELECT * FROM {pay_method} WHERE STATUS = 1 ORDER BY title");
  while ($row = db_fetch_object($res)) {
    $list[$row->pmid] = pay_method_load($row);
  }
  return $list;
}

/**
 * Helper function to list all possible currencies.
 *
 * This function returns a superset of all currencies supported by all payment
 * methods installed on this site.
 */
function pay_currency_list() {
  static $list;
  if (!isset($list)) {

    // Gather a list of all supported currencies.
    $currencies = $list = array();
    foreach (pay_handlers('pay_method') as $name => $info) {
      if ($method = pay_method_load($name)) {
        $currencies = array_merge($currencies, $method
          ->available_currencies());
      }
    }

    // Create a sorted key => value array.
    foreach ($currencies as $item) {
      $list[$item] = $item;
    }
    ksort($list);
    drupal_alter('pay_currency_list', $list);
  }
  return $list;
}

/**
 * Callback for pay activity responses.
 */
function pay_gateway_response($pay_activity) {

  // Add an additional activity to the transaction to track the response.
  $new_activity = $pay_activity
    ->pay_transaction()
    ->add_activity($pay_activity
    ->pay_method());
  $new_activity
    ->do_activity('response', $_REQUEST);
}

/**
 * Return a list of available transaction states.
 */
function pay_transaction_states($state = NULL) {
  static $states;
  if (!isset($states)) {
    $states = array();
    foreach (pay_transaction_load()
      ->states() as $name => $info) {
      $states[$name] = $info['title'];
    }
  }
  if (isset($state)) {
    return $states[$state];
  }
  return $states;
}

/**
 * Return the 'nice' name for payment transaction states.
 */
function pay_transaction_state_name($state) {

  // It's a transaction object?  Function as a wrapper for its state() method.
  if (is_object($state)) {
    return $state
      ->state(TRUE);
  }

  // Or else just return the label based on this name.
  return pay_transaction_states($state);
}

/**
 * Wrapper for $pay_transaction->valid_action(), to be used as a menu callback.
 */
function pay_transaction_valid_action($pay_transaction, $action) {

  // Not a valid action for this transaction.  Skip it and return FALSE.
  if (!$pay_transaction
    ->valid_action($action)) {
    return FALSE;
  }

  // Return TRUE for payment administrators for this/all forms.
  if (user_access('administer payments for any form')) {
    return TRUE;
  }
  $handler = $pay_transaction
    ->pay_form()
    ->handler();
  if (user_access('administer payments for ' . $handler . ' forms')) {
    return TRUE;
  }

  // Give up and return false.
  return FALSE;
}

/**
 * Wrapper for $pay_transaction->do_action(), to be used as a menu callback.
 */
function pay_transaction_do_action($transaction, $action, $path = FALSE) {
  if ($transaction
    ->do_action($action)) {
    $info = $transaction->valid_actions[$action];
    if ($info['message']) {
      drupal_set_message($info['message']);
    }
  }

  // Redirect to the transaction page or the front page if it has been deleted.
  if ($path) {
    if ($path === TRUE) {
      $path = 'pay/transaction/' . $transaction->pxid;
      if ($action == 'delete') {
        $path = '<front>';
      }
    }
    drupal_goto($path);
  }
}

/**
 * Title callback for a page that effects a payment transaction action.
 */
function pay_transaction_action_title($pay_transaction, $action) {
  if ($info = $pay_transaction
    ->valid_actions($action)) {
    return t('@title transaction', array(
      '@title' => $info['title'],
    ));
  }
}

Functions

Namesort descending Description
pay_activity_load API Function: Load a payment activity object.
pay_after_build A FAPI after_build handler for any type of pay form.
pay_currency_list Helper function to list all possible currencies.
pay_element_set_required A helper function to be used as a #pre_render callback: Sets an element to "required" for rendering. The calling code should handle validation responsibly.
pay_form A simple form any type of pay element. If you want to build a module with a standalone payment form, you would do so by passing this function to the drupal_get_form page handler in your hook_menu() funcion.
pay_forms_list List available payment forms.
pay_form_alter Implements hook_form_alter(). Pass the form to any applicable pay handlers in case they have some input.
pay_form_callback A helper function for FAPI validate/submit callbacks. Locates any pay elements in a form and calls thier handler code.
pay_form_displays List of meaningful ways in which a payment form can appear.
pay_form_displays_list Name/value List of meaningful ways in which a payment form can appear.
pay_form_load API Function: Load a payment form object.
pay_gateway_response Callback for pay activity responses.
pay_handlers API Function: All available payment handlers.
pay_init Implements hook_init().
pay_item_load API Function: Load a payment item object.
pay_load_handler API Function: Include a handler file for a payment object.
pay_load_object API Function: Load a payment class.
pay_menu Implements hook_menu().
pay_method_list Helper function to list all payment methods available.
pay_method_load API Function: Load a payment method object.
pay_permission Implements hook_permission().
pay_submit A FAPI submit handler for any type of pay form.
pay_theme Implements hook_theme().
pay_transaction_action_title Title callback for a page that effects a payment transaction action.
pay_transaction_do_action Wrapper for $pay_transaction->do_action(), to be used as a menu callback.
pay_transaction_load API Function: Load a payment transaction object.
pay_transaction_states Return a list of available transaction states.
pay_transaction_state_name Return the 'nice' name for payment transaction states.
pay_transaction_valid_action Wrapper for $pay_transaction->valid_action(), to be used as a menu callback.
pay_user_cancel Implements hook_user_cancel().
pay_user_categories Implements hook_user_categories().
pay_user_settings_access An access callback for access to user-specific Payment settings form.
pay_user_settings_form A form callback for a user's 'Payment settings' page.
pay_user_settings_page Form builder; Present the form to edit a user's payment settings.
pay_validate A FAPI validate handler for any type of pay form.
pay_views_api Implements hook_views_api().