You are here

uc_recurring_order.module in UC Recurring Payments and Subscriptions 6.2

Same filename and directory in other branches
  1. 7.2 modules/uc_recurring_order/uc_recurring_order.module

Provides a way to duplicate entire orders.

Initial module development sponsored by River Valley Tech Collective http://www.rvtc.us/

File

modules/uc_recurring_order/uc_recurring_order.module
View source
<?php

/**
 * @file
 * Provides a way to duplicate entire orders.
 *
 * Initial module development sponsored by River Valley Tech Collective
 * http://www.rvtc.us/
 */

/**
 * Implementation of hook_init().
 */
function uc_recurring_order_init() {
  module_load_include('inc', 'uc_recurring_order', 'uc_recurring_order.ca');
}

/**
 * Implementation of hook_menu().
 */
function uc_recurring_order_menu() {
  $items['admin/store/settings/orders/edit/recurring'] = array(
    'title' => 'Recurring orders',
    'description' => 'Edit recurring order information.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'uc_recurring_order_settings_form',
    ),
    'access arguments' => array(
      'administer store',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 0,
  );
  return $items;
}

/**
 * Settings for recurring orders
 */
function uc_recurring_order_settings_form($form) {
  drupal_set_title(t('Recurring Order Settings'));
  $intervals = variable_get('uc_recurring_order_interval_options', array());
  foreach ($intervals as $int => $value) {
    $options[] = $int . '|' . $value;
  }
  $options = !empty($options) ? implode("\n", $options) : '';
  $form = array();
  $form['interval_options'] = array(
    '#type' => 'textarea',
    '#required' => TRUE,
    '#default_value' => $options,
    '#title' => t('Available Recurring Interval Options'),
    '#description' => t('Enter one allowed interval per line, in the format time|label, for example: 1 day|Daily.  Times must be in valid <a href="@link">strotime</a> format.  To enter a 0 value (non-recurring), make sure to enter valid strotime such as "0 months"', array(
      '@link' => url('http://php.net/manual/en/function.strtotime.php'),
    )),
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}
function uc_recurring_order_settings_form_validate($form, &$form_state) {
  $options = preg_split('/[\\r\\n]+/', $form_state['values']['interval_options']);
  $errors = '';
  foreach ($options as $key => $value) {
    $i = explode('|', $value);
    if (strtotime($i[0])) {
      $intervals[$i[0]] = isset($i[1]) && $i[1] !== '' ? $i[1] : $i[0];
    }
    else {
      $errors .= t('!error is not valid strtotime format <br />', array(
        '!error' => $i[0],
      ));
    }
  }
  if (!empty($errors)) {
    return form_set_error('interval_options', $errors);
  }
  $form_state['values']['intervals'] = $intervals;
}
function uc_recurring_order_settings_form_submit($form, &$form_state) {
  variable_set('uc_recurring_order_interval_options', $form_state['values']['intervals']);
  drupal_set_message(t('The recurring options have been saved.'));
}

/**
 * Callback function to return interval options
 *
 * @return
 *   An array of interval options
 */
function uc_recurring_order_get_intervals() {
  $options = variable_get('uc_recurring_order_interval_options', array());
  foreach ($options as $key => $option) {
    $options[check_plain($key)] = check_plain($option);
  }
  return $options;
}

/**
 * Implementation of hook_cart_pane().
 */
function uc_recurring_order_cart_pane($items) {
  $panes[] = array(
    'id' => 'recurring',
    'body' => drupal_get_form('uc_recurring_order_pane_cart'),
    'title' => t('Recurring order'),
    'desc' => t("Allows shoppers to select to have their order automatically re-occur."),
    'weight' => 1,
    'enabled' => TRUE,
  );
  return $panes;
}

/**
 * Cart pane recurring form.
 */
function uc_recurring_order_pane_cart($form_state) {
  $intervals = uc_recurring_order_get_intervals();
  if (empty($intervals)) {
    return;
  }
  $form['recurring_option'] = array(
    '#type' => 'select',
    '#title' => t('Recurring Order'),
    '#description' => t('Select to have this order automatically repeat.'),
    '#options' => $intervals,
    '#default_value' => $_SESSION['recurring_option'],
  );
  $form['apply'] = array(
    '#type' => 'submit',
    '#value' => t('Apply to order'),
  );
  return $form;
}
function uc_recurring_order_pane_cart_submit($form, &$form_state) {
  if ($form_state['values']['recurring_option']) {
    $recurring_option = $form_state['values']['recurring_option'];
    $next_renewal = strtotime('+' . $recurring_option);
    if ($next_renewal > time()) {
      $_SESSION['recurring_option'] = $recurring_option;
      drupal_set_message(t('Your next order after this will occur on @next.', array(
        '@recurring' => $recurring_options[$recurring],
        '@next' => format_date($next_renewal, 'short'),
      )));
    }
    else {
      unset($_SESSION['recurring_option']);
    }
  }
}

/**
 * Implementation of hook_checkout_pane().
 *
 * Show a pane just above the order total that allows shoppers to select
 * recurring option for the order.
 */
function uc_recurring_order_checkout_pane() {
  $panes[] = array(
    'id' => 'recurring',
    'callback' => 'uc_recurring_order_pane_checkout',
    'title' => t('Recurring Order'),
    'desc' => t("Allows shoppers to select to have their order automatically re-occur."),
    'weight' => 5,
    'process' => TRUE,
  );
  return $panes;
}

/**
 * Checkout Pane callback function.
 *
 * Used to display a form in the checkout process so that customers
 * can select recurring/repeat option.
 */
function uc_recurring_order_pane_checkout($op, &$arg1, $arg2) {
  switch ($op) {
    case 'view':
      $intervals = uc_recurring_order_get_intervals();
      if (empty($intervals)) {
        return;
      }

      // Use recurring order info from cart pane if available.
      if ($_SESSION['recurring_option']) {
        $recurring = $_SESSION['recurring_option'];
        unset($_SESSION['recurring_option']);
      }
      else {
        $recurring = $arg1->data['recurring_option'];
      }
      $description = t('Select to have this order automatically repeat.');
      $contents['recurring_option'] = array(
        '#type' => 'select',
        '#title' => t('Recurring Order'),
        '#default_value' => $recurring,
        '#options' => $intervals,
      );
      return array(
        'description' => $description,
        'contents' => $contents,
      );
    case 'process':

      // Can't renew orders that include product with recurring payments.
      if (module_exists('uc_recurring_product')) {
        if ($products = uc_recurring_product_get_recurring_products_in_order($order)) {
          unset($_SESSION['recurring_option']);
          drupal_set_message(t('Unable to create recurring order when it contains recurring products'), 'warning');
          return FALSE;
        }
      }
      $recurring = $arg2['recurring_option'];
      $next_renewal = strtotime('+' . $recurring);
      if ($next_renewal > time()) {
        $arg1->data['recurring_option'] = $recurring;
      }
      else {
        unset($_SESSION['recurring_option']);
      }
      return TRUE;
    case 'review':
      if ($arg1->data['recurring_option']) {
        $next_renewal = strtotime('+' . $arg1->data['recurring_option']);
        $review[] = array(
          'title' => t('Recurring Order'),
          'data' => t('Your next order after this will occur on @next.', array(
            '@recurring' => $arg1->data['recurring_option'],
            '@next' => format_date($next_renewal, 'short'),
          )),
        );
      }
      return $review;
  }
}

/**
 * Implementation of hook_order().
 */
function uc_recurring_order_order($op, $arg1, $arg2) {
  switch ($op) {

    // TODO: Allow admin to create a recurring order from "create order" page.
    case 'submit':
      $recurring = $arg1->data['recurring_option'];
      $next_renewal = strtotime('+' . $recurring);
      if ($next_renewal > time() && variable_get('uc_recurring_checkout_process', TRUE)) {
        if (uc_recurring_order_process_order($arg1, $recurring) === FALSE) {
          return array(
            array(
              'pass' => FALSE,
              'message' => t('Your order cannot be completed, because we could not process your recurring payment. Please review your payment details and contact us to complete your order if the problem persists.'),
            ),
          );
        }
      }
      break;
    case 'save':
      if (isset($arg1->data['recurring_option'])) {

        // Only update when this is a recurring order
        db_query("UPDATE {uc_recurring_users} SET fee_amount = %f WHERE order_id = %d", uc_order_get_total($arg1), $arg1->order_id);
        if (db_affected_rows() !== 0) {
          uc_order_comment_save($arg1->order_id, 0, t('The recurring order amount was updated.'), 'admin');
        }
      }
      break;
  }
}

/**
 * Process a recurring order.
 */
function uc_recurring_order_process_order($order, $recurring) {
  if (variable_get('uc_recurring_order_enabled', TRUE)) {
    $payment_method = !empty($order->payment_method) ? $order->payment_method : 'default';
    if (!($fee_handler = uc_recurring_get_recurring_info($payment_method))) {
      drupal_set_message(t('A handler for processing and renewing recurring fees cannot be found for the @payment-method payment method.', array(
        '@payment-method' => $order->payment_method,
      )), 'error');
      return FALSE;
    }

    // Create a new fee object.
    $fee = new stdClass();
    $fee->uid = $order->uid;
    $fee->fee_handler = $fee_handler['fee handler'];
    $fee->created = time();
    $fee->order_id = $order->order_id;

    // If the product fee amount is 0, it means we need to use the product
    // price. This allows recurring fees to be adjusted by attributes.
    $fee->fee_amount = $order->order_total;

    // Add the order's ID as the order title.
    $fee->fee_title = t('Renewal of order @order_id', array(
      '@order_id' => $order->order_id,
    ));
    $fee->next_charge = strtotime('+' . $recurring);
    $fee->regular_interval = $recurring;
    $fee->remaining_intervals = -1;

    // hard coded to unlimited
    $fee->charged_intervals = 0;
    $products = $order->products;
    foreach ($products as $index => $product) {
      unset($products[$index]->order_product_id);
      unset($products[$index]->order_id);
    }
    $fee->data = array(
      'uc_recurring_order' => array(
        'products' => $products,
      ),
    );
    $fee->attempts = 0;
    $fee->pfid = NULL;
    $fee->order_product_id = NULL;
    $fee->own_handler = !empty($fee_handler['own handler']);
    drupal_alter('recurring_fee_user_create', $fee);
    if (uc_recurring_invoke($fee->fee_handler, 'process callback', array(
      $order,
      &$fee,
    ))) {
      $rfid = uc_recurring_fee_user_save($fee);
      uc_order_comment_save($order->order_id, $user->uid, t('Recurring fee <a href="@recurring-view-fee">@rfid</a> added to order.', array(
        '@recurring-view-fee' => url('admin/store/orders/recurring/view/fee/' . $rfid),
        '@rfid' => $rfid,
      )));
    }
    else {
      return FALSE;
    }
  }
  return $return;
}

/**
 * Implements hook_recurring_renewal_pending()
 */
function uc_recurring_order_recurring_renewal_pending(&$order, $fee) {

  // recreate order
  if (!empty($fee->data['uc_recurring_order'])) {
    $order->products = $fee->data['uc_recurring_order']['products'];
    $result = db_query("SELECT * FROM {uc_order_line_items} WHERE order_id = %d", $fee->order_id);
    while ($line_item = db_fetch_array($result)) {
      uc_order_line_item_add($order->order_id, $line_item['type'], $line_item['title'], $line_item['amount'], $line_item['weight'], $line_item['data']);
    }
  }
}

/**
 * Alter the Edit screen to show the products in the order.
 */
function uc_recurring_order_form_uc_recurring_admin_edit_form_alter(&$form, $form_state) {
  $rfid = $form['#parameters'][2];
  $fee = uc_recurring_fee_user_load($rfid);
  if ($fee->data['uc_recurring_order']) {
    foreach ($fee->data['uc_recurring_order']['products'] as $product) {
      $row = array(
        'title' => $product->title,
        'qty' => $product->qty,
        'price' => $product->price,
      );
      $rows[] = $row;
    }
    $form['products'] = array(
      '#type' => 'fieldset',
      '#title' => t('Products'),
      '#description' => theme('table', array(
        'Product',
        'Quantity',
        'Price',
      ), $rows),
      '#weight' => -10,
    );
  }
}