diff --git modules/uc_recurring_order/uc_recurring_order.info modules/uc_recurring_order/uc_recurring_order.info
new file mode 100644
index 0000000..d9bdd3d
--- /dev/null
+++ modules/uc_recurring_order/uc_recurring_order.info
@@ -0,0 +1,5 @@
+name = Recurring Fees - Order
+description = Recurring Fees for duplicating entire orders.
+dependencies[] = uc_recurring
+package = Ubercart - payment
+core = 6.x
diff --git modules/uc_recurring_order/uc_recurring_order.module modules/uc_recurring_order/uc_recurring_order.module
new file mode 100644
index 0000000..229c773
--- /dev/null
+++ modules/uc_recurring_order/uc_recurring_order.module
@@ -0,0 +1,360 @@
+<?php
+// $Id:$
+
+/**
+ * @file
+ * Provides a way to duplicate entire orders.
+ *
+ * Initial module development sponsored by River Valley Tech Collective
+ * http://www.rvtc.us/
+ */
+
+/**
+ * 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_state) {
+  drupal_set_title(t('Recurring Order Settings'));
+  $intoptions = _uc_recurring_order_recurring_options();
+  $form['pane_settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Pane Text Settings'),
+    '#collapsible' => TRUE,
+  );
+  $form['pane_settings']['uc_recurring_order_pane_description'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Checkout pane message'),
+    '#default_value' => t(variable_get('uc_recurring_pane_description', 'Select to have this order automatically repeat,')),
+  );
+  $form['pane_settings']['uc_recurring_order_pane_title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Checkout and Review Pane Title'),
+    '#default_value' => t(variable_get('uc_recurring_order_pane_title', 'Recurring Order')),
+  );
+  $form['pane_settings']['uc_recurring_order_pane_empty'] = array(
+    '#type' => 'textarea',
+    '#title' => t('No Recurring Order Text'),
+    '#description' => t('Text to display on the order review page if customer has not signed up for a recurring order.'),
+    '#default_value' => t(variable_get('uc_recurring_order_pane_empty', 'This order will not repeat.')),
+  );
+  $form['interval_options'] = array(
+    '#type' => 'select',
+    '#multiple' => TRUE,
+    '#options' => $intoptions,
+    '#default_value' => variable_get('uc_recurring_order_interval_options', $intoptions),
+    '#title' => t('Available Recurring Interval Options'),
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+
+  return $form;
+}
+
+function uc_recurring_order_settings_form_submit($form, &$form_state) {
+  $intervals = array();
+  foreach ($form_state['values']['interval_options'] as $int => $option) {
+    $intervals[check_plain($option)] = check_plain($option);
+  }
+  variable_set('uc_recurring_order_interval_options', $intervals);
+  variable_set('uc_recurring_pane_description', check_plain($form_state['values']['uc_recurring_order_pane_description']));
+  variable_set('uc_recurring_order_pane_title', check_plain($form_state['values']['uc_recurring_order_pane_title']));
+  variable_set('uc_recurring_order_pane_empty', check_plain($form_state['values']['uc_recurring_order_pane_empty']));
+}
+
+
+/**
+ * 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) {
+  $options = array();
+  $intervals = variable_get('uc_recurring_order_interval_options', _uc_recurring_order_recurring_options());
+  $values = _uc_recurring_order_recurring_options();
+  foreach ($intervals as $int => $option) {
+    $options[$option] = $values[$option];
+  }
+
+  $form['recurring_option'] = array(
+    '#type' => 'select',
+    '#title' => t(variable_get('uc_recurring_order_pane_title', 'Recurring Order')),
+    '#description' => t(variable_get('uc_recurring_pane_description', 'Select to have this order automatically repeat,')),
+    '#options' => $options,
+    '#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_options = _uc_recurring_order_recurring_options();
+    $recurring_option = check_plain($form_state['values']['recurring_option']);
+    $next_renewal = strtotime('+'. $recurring_option);
+    if ($next_renewal > 0) {
+      $_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['uc_recurring_order']);
+    }
+  }
+}
+
+/**
+ * Default options
+ */
+function _uc_recurring_order_recurring_options() {
+  return array(
+    '0 months' => t('Single order (not recurring)'),
+    '1 months' => t('Monthly order'),
+    '3 months' => t('Every Three Months'),
+    '6 months' => t('Every 6 Months'),
+    '12 months' => t('Once a year'),
+  );
+}
+
+/**
+ * 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':
+      $options = array();
+      $intervals = variable_get('uc_recurring_order_interval_options', _uc_recurring_order_recurring_options());
+      $values = _uc_recurring_order_recurring_options();
+      foreach ($intervals as $int => $option) {
+        $options[$option] = $values[$option];
+      }
+
+      // 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.');
+      $contents['recurring_option'] = array(
+        '#type' => 'select',
+        '#title' => t(variable_get('uc_recurring_order_pane_title', 'Recurring Order')),
+        '#default_value' => $recurring,
+        '#options' => $options,
+      );
+      return array('description' => $description, 'contents' => $contents);
+
+    case 'process':
+      // Can't renew orders that include product with recurring payments.
+      if (($products = uc_recurring_get_recurring_products_in_order($order))) {
+        unset($_SESSION['uc_recurring_order']);
+        drupal_set_message(t('Unable to create recurring order when it contains recurring products'), 'warning');
+        return FALSE;
+      }
+
+      if ($arg2['recurring_option']) {
+        $recurring_options = _uc_recurring_order_recurring_options();
+        $recurring = check_plain($arg2['recurring_option']);
+        $next_renewal = strtotime('+'. $recurring);
+        if ($next_renewal > 0) {
+          $arg1->data['recurring_option'] = $recurring;
+        }
+        else {
+          unset($_SESSION['recurring']);
+        }
+      }
+      return TRUE;
+
+    case 'review':
+      if ($arg1->data['recurring_option']) {
+        $next_renewal = strtotime('+'. $arg1->data['recurring_option']);
+        $review[] = array('title' =>t(variable_get('uc_recurring_order_pane_title', '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'))));
+      }
+      else {
+        $review[] = array('title' =>t(variable_get('uc_recurring_order_pane_title', 'Recurring Order')), 'data' => t(variable_get('uc_recurring_order_pane_empty', 'This order will not repeat.')));
+      }
+     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':
+      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 product's title as the order title.
+    $fee->fee_title = t('Renewal of product @title', array('@title' => $product['product']->title));
+
+    $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,
+      ),
+      'recurring orders' => array(),
+    );
+    $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,
+    );
+  }
+}
diff --git uc_recurring.install uc_recurring.install
index 3233d1a..22aa060 100644
--- uc_recurring.install
+++ uc_recurring.install
@@ -171,7 +171,7 @@ function uc_recurring_schema() {
         'description' => 'The product ID.',
         'type' => 'int',
         'unsigned' => TRUE,
-        'not null' => TRUE,
+        'not null' => FALSE,
         'default' => 0,
       ),
       'own_handler' => array(
@@ -496,3 +496,12 @@ function uc_recurring_update_6008() {
   
   return $ret;
 }
+
+/**
+ * Allow product ID to be NULL if this recurring fee is not for a specific product.
+ */
+function uc_recurring_update_6009() {
+  $ret = array();
+  db_change_field($ret, 'uc_recurring_users', 'order_product_id', 'order_product_id', array('type' => 'int', 'size' => 'small', 'unsigned' => TRUE, 'not null' => FALSE, 'default' => 0));
+  return $ret;
+}
