From 377719d5360147a480a18ea4129d99e6f709f419 Mon Sep 17 00:00:00 2001
From: wodenx <wodenx@896508.no-reply.drupal.org>
Date: Sun, 18 Dec 2011 01:20:36 +0000
Subject: [PATCH 1/2] Issue #1298550: Create new 'abandoned' order status.

---
 uc_cart/tests/uc_cart.test |   79 ++++++++++++++++++++++++++++++++++++++++++++
 uc_cart/uc_cart.module     |    8 ++++
 uc_cart/uc_cart.pages.inc  |    5 ++-
 uc_order/uc_order.install  |   22 ++++++++++++
 4 files changed, 113 insertions(+), 1 deletions(-)

diff --git a/uc_cart/tests/uc_cart.test b/uc_cart/tests/uc_cart.test
index 05944c9..5caa378 100644
--- a/uc_cart/tests/uc_cart.test
+++ b/uc_cart/tests/uc_cart.test
@@ -269,6 +269,85 @@ class UbercartCartCheckoutTestCase extends UbercartTestHelper {
     $this->assertEqual(count($mails), 2, '2 e-mails were sent.');
     variable_del('drupal_test_email_collector');
   }
+
+  /**
+   * Tests that cart orders are marked abandoned after a timeout.
+   */
+  function testCartOrderTimeout() {
+    $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
+    $this->drupalPost('cart', array(), 'Checkout');
+    $this->assertText(
+      t('Enter your billing address and information here.'),
+      t('Viewed cart page: Billing pane has been displayed.')
+    );
+
+    // Build the panes.
+    $zone_id = db_query('SELECT zone_id FROM {uc_zones} WHERE zone_country_id = :country ORDER BY rand() LIMIT 1', array('country' => variable_get('uc_store_country', 840)))->fetchField();
+    $oldname = $this->randomName(10);
+    $edit = array(
+      'panes[delivery][delivery_first_name]' => $oldname,
+      'panes[delivery][delivery_last_name]' => $this->randomName(10),
+      'panes[delivery][delivery_street1]' => $this->randomName(10),
+      'panes[delivery][delivery_city]' => $this->randomName(10),
+      'panes[delivery][delivery_zone]' => $zone_id,
+      'panes[delivery][delivery_postal_code]' => mt_rand(10000, 99999),
+
+      'panes[billing][billing_first_name]' => $this->randomName(10),
+      'panes[billing][billing_last_name]' => $this->randomName(10),
+      'panes[billing][billing_street1]' => $this->randomName(10),
+      'panes[billing][billing_city]' => $this->randomName(10),
+      'panes[billing][billing_zone]' => $zone_id,
+      'panes[billing][billing_postal_code]' => mt_rand(10000, 99999),
+    );
+
+    // If the email address has not been set, and the user has not logged in,
+    // add a primary email address.
+    if (!isset($edit['panes[customer][primary_email]']) && !$this->loggedInUser) {
+      $edit['panes[customer][primary_email]'] = $this->randomName(8) . '@example.com';
+    }
+
+    // Submit the checkout page.
+    $this->drupalPost('cart/checkout', $edit, t('Review order'));
+
+    $order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(':name' => $oldname))->fetchField();
+    if ($order_id) {
+      // Go to a different page, then back to order - make sure order_id is the same.
+      $this->drupalGet('<front>');
+      $this->drupalPost('node/' . $this->product->nid, array(), t('Add to cart'));
+      $this->drupalPost('cart', array(), 'Checkout');
+      $this->assertRaw($oldname, 'Customer name was unchanged.');
+      $this->drupalPost('cart/checkout', $edit, t('Review order'));
+      $new_order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(':name' => $edit['panes[delivery][delivery_first_name]']))->fetchField();
+      $this->assertEqual($order_id, $new_order_id, 'Original order_id was reused.');
+
+      // Jump 10 minutes into the future.
+      db_update('uc_orders')
+        ->fields(array(
+            'modified' => time() - UC_CART_ORDER_TIMEOUT - 1,
+          ))
+        ->condition('order_id', $order_id)
+        ->execute();
+      $old_order = uc_order_load($order_id);
+
+      // Go to a different page, then back to order - verify that we are using a new order.
+      $this->drupalGet('<front>');
+      $this->drupalPost('cart', array(), 'Checkout');
+      $this->assertNoRaw($oldname, 'Customer name was cleared after timeout.');
+      $newname = $this->randomName(10);
+      $edit['panes[delivery][delivery_first_name]'] = $newname;
+      $this->drupalPost('cart/checkout', $edit, t('Review order'));
+      $new_order_id = db_query("SELECT order_id FROM {uc_orders} WHERE delivery_first_name = :name", array(':name' => $newname))->fetchField();
+      $this->assertNotEqual($order_id, $new_order_id, 'New order was created after timeout.');   
+
+      // Verify that the status of old order is abandoned.
+      $old_order = uc_order_load($order_id, TRUE);
+      $this->assertEqual($old_order->order_status, 'abandoned', 'Original order was marked abandoned.');
+    }
+    else {
+      $this->fail('No order was created.');
+    }
+  }
+
 }
 
 /**
diff --git a/uc_cart/uc_cart.module b/uc_cart/uc_cart.module
index d42eb2c..c829bf2 100644
--- a/uc_cart/uc_cart.module
+++ b/uc_cart/uc_cart.module
@@ -11,6 +11,7 @@
  */
 
 require_once('uc_cart_checkout_pane.inc');
+define('UC_CART_ORDER_TIMEOUT', 600); // Time in seconds after which a cart order is deemed abandoned.
 
 /*******************************************************************************
  * Hook Functions (Drupal)
@@ -221,6 +222,13 @@ function uc_cart_cron() {
       uc_cart_empty($row->cart_id);
     }
   }
+
+  // Update status of abandoned orders.
+  $result = db_query("SELECT order_id FROM {uc_orders} WHERE order_status = :status AND modified < :time",
+    array(':status' => 'in_checkout', ':time' => REQUEST_TIME - UC_CART_ORDER_TIMEOUT))->fetchCol();
+  foreach ($result as $order_id) {
+    uc_order_update_status($order_id, 'abandoned');
+  }
 }
 
 /**
diff --git a/uc_cart/uc_cart.pages.inc b/uc_cart/uc_cart.pages.inc
index b6fc686..f2b83c8 100644
--- a/uc_cart/uc_cart.pages.inc
+++ b/uc_cart/uc_cart.pages.inc
@@ -113,7 +113,10 @@ function uc_cart_checkout_form($form, &$form_state) {
 
   // If there hasn't been activity on the checkout page for 20 minutes, clear
   // order details and prevent identity theft.
-  if (!$order || uc_order_status_data($order->order_status, 'state') != 'in_checkout' || $order->modified < REQUEST_TIME - 600 || ($user->uid > 0 && $user->uid != $order->uid)) {
+  if (!$order || uc_order_status_data($order->order_status, 'state') != 'in_checkout' || $order->modified < REQUEST_TIME - UC_CART_ORDER_TIMEOUT || ($user->uid > 0 && $user->uid != $order->uid)) {
+    if ($order && uc_order_status_data($order->order_status, 'state')  == 'in_checkout' && $order->modified < REQUEST_TIME - UC_CART_ORDER_TIMEOUT) {
+      uc_order_update_status($order->order_id, 'abandoned');
+    }
     $order = uc_order_new($user->uid);
     $_SESSION['cart_order'] = $order->order_id;
   }
diff --git a/uc_order/uc_order.install b/uc_order/uc_order.install
index 025257e..38f59b1 100644
--- a/uc_order/uc_order.install
+++ b/uc_order/uc_order.install
@@ -610,6 +610,13 @@ function uc_order_install() {
 
   $values = array(
     array(
+      'order_status_id' => 'abandoned',
+      'title' => $t('Abandoned'),
+      'state' => 'canceled',
+      'weight' => -30,
+      'locked' => 1,
+    ),
+    array(
       'order_status_id' => 'canceled',
       'title' => $t('Canceled'),
       'state' => 'canceled',
@@ -816,3 +823,18 @@ function uc_order_update_7005() {
 function uc_order_update_7006() {
   variable_del('uc_order_number_displayed');
 }
+
+/**
+ * Add 'abandoned' order status.
+ */
+function uc_order_update_7007() {
+  db_merge('uc_order_statuses')
+    ->key(array('order_status_id' => 'abandoned'))
+    ->fields(array(
+      'title' => t('Abandoned'),
+      'state' => 'canceled',
+      'weight' => -30,
+      'locked' => 1,
+    ))
+    ->execute();
+}
-- 
1.7.4.1


From ed150b005333ad5ff97da8018e0c0978190caa04 Mon Sep 17 00:00:00 2001
From: Dave Long <dave@longwaveconsulting.com>
Date: Sun, 18 Dec 2011 02:04:24 +0000
Subject: [PATCH 2/2] Issue #1298550: Abandon old 'in checkout' orders in update.php.

---
 uc_order/uc_order.install |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/uc_order/uc_order.install b/uc_order/uc_order.install
index 38f59b1..15f8710 100644
--- a/uc_order/uc_order.install
+++ b/uc_order/uc_order.install
@@ -837,4 +837,10 @@ function uc_order_update_7007() {
       'locked' => 1,
     ))
     ->execute();
+
+  db_update('uc_orders')
+    ->fields(array('order_status' => 'abandoned'))
+    ->condition('order_status', 'in_checkout')
+    ->condition('modified', REQUEST_TIME - 600, '<')
+    ->execute();
 }
-- 
1.7.4.1

