uc_recurring_order.module in UC Recurring Payments and Subscriptions 6.2
Same filename and directory in other branches
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.moduleView 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,
);
}
}
Functions
Name | Description |
---|---|
uc_recurring_order_cart_pane | Implementation of hook_cart_pane(). |
uc_recurring_order_checkout_pane | Implementation of hook_checkout_pane(). |
uc_recurring_order_form_uc_recurring_admin_edit_form_alter | Alter the Edit screen to show the products in the order. |
uc_recurring_order_get_intervals | Callback function to return interval options |
uc_recurring_order_init | Implementation of hook_init(). |
uc_recurring_order_menu | Implementation of hook_menu(). |
uc_recurring_order_order | Implementation of hook_order(). |
uc_recurring_order_pane_cart | Cart pane recurring form. |
uc_recurring_order_pane_cart_submit | |
uc_recurring_order_pane_checkout | Checkout Pane callback function. |
uc_recurring_order_process_order | Process a recurring order. |
uc_recurring_order_recurring_renewal_pending | Implements hook_recurring_renewal_pending() |
uc_recurring_order_settings_form | Settings for recurring orders |
uc_recurring_order_settings_form_submit | |
uc_recurring_order_settings_form_validate |