Index: uc_restrict_qty.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_restrict_qty/uc_restrict_qty.info,v
retrieving revision 1.1.4.2
diff -u -r1.1.4.2 uc_restrict_qty.info
--- uc_restrict_qty.info	17 Oct 2008 14:41:03 -0000	1.1.4.2
+++ uc_restrict_qty.info	11 May 2009 17:41:58 -0000
@@ -1,6 +1,6 @@
 ; $Id: uc_restrict_qty.info,v 1.1.4.2 2008/10/17 14:41:03 mrfelton Exp $
-name = Restrict Qty
-description = Restrict the quantity on specified products so that only one may be purchased at a time.
+name = UC Restrict Qty
+description = Restrict the quantity on specified products so that only specified quantity may be purchased at a time.
 dependencies[] = uc_cart
 package = Ubercart - extra
 core = 6.x
\ No newline at end of file
Index: uc_restrict_qty.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_restrict_qty/Attic/uc_restrict_qty.install,v
retrieving revision 1.1.2.2
diff -u -r1.1.2.2 uc_restrict_qty.install
--- uc_restrict_qty.install	11 May 2009 17:28:55 -0000	1.1.2.2
+++ uc_restrict_qty.install	13 May 2009 17:33:30 -0000
@@ -47,6 +47,14 @@
         'not null' => TRUE,
         'default' => 0,
       ),
+      'lifetime' => array(
+        'description' => t('Is restriction lifetime?'),
+        'type' => 'int',
+        'size' => 'tiny',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 1,
+      ),
     ),
     'indexes' => array(
       'nid' => array('nid'),
@@ -81,10 +89,20 @@
 /**
  * Implementation of hook_update_N().
  *
-* If updating from an earlier version than 6.x-2.0, the database needs to be installed.
-*/
+ * If updating from an earlier version than 6.x-2.0, the database needs to be installed.
+ */
 function uc_restrict_qty_update_6200() {
   $ret = array();
   uc_restrict_qty_install();
   return $ret;
 }
+
+
+/**
+ * Add lifetime value to the scheme.
+ */
+function uc_restrict_qty_update_6201() {
+  $ret = array();
+  db_add_field($ret, 'uc_restrict_qty_products', 'lifetime', array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 1));
+  return $ret;
+}
Index: uc_restrict_qty.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_restrict_qty/uc_restrict_qty.module,v
retrieving revision 1.1.4.5.2.2
diff -u -r1.1.4.5.2.2 uc_restrict_qty.module
--- uc_restrict_qty.module	13 Apr 2009 11:21:15 -0000	1.1.4.5.2.2
+++ uc_restrict_qty.module	13 May 2009 17:26:08 -0000
@@ -3,7 +3,7 @@
 
 /**
  * @file
- * Restrict the quantity on specified products so that only one may be purchased
+ * Restrict the quantity on specified products so that only specified quantity may be purchased
  * at a time.
  */
 
@@ -43,7 +43,27 @@
     '#size' => 5,
     '#maxlength' => 5,
     '#description' => t('The number of different products that can be added to a cart. Set to 0 for unlimited.'),
-    '#default_value' => variable_get('uc_restrict_qty_global', '0'),
+    '#default_value' => variable_get('uc_restrict_qty_global', 0),
+  );
+
+  $form['defaults'] = array(
+    '#title' => t('Defaults'),
+    '#type' => 'fieldset',
+    '#description' => t('These options will take action, only if product has the "Restrict quantity" feature activated.'),
+  );
+  $form['defaults']['uc_restrict_qty_default_qty'] = array(
+    '#title' => t("Default maximum limit for a product"),
+    '#type' => 'textfield',
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#description' => t('The number of products of single type that can be added to a cart. Set to 0 for unlimited.'),
+    '#default_value' => variable_get('uc_restrict_qty_default_qty', 0),
+  );
+  $form['defaults']['uc_restrict_qty_default_lifetime'] = array(
+    '#title' => t("Is restriction is the user's lifetime limit"),
+    '#type' => 'checkbox',
+    '#description' => t("Useful when you want to prevent double ordering of a product."),
+    '#default_value' => variable_get('uc_restrict_qty_default_lifetime', TRUE),
   );
 
   return $form;
@@ -54,6 +74,9 @@
   if (!is_numeric($form_state['values']['uc_restrict_qty_global']) || $form_state['values']['uc_restrict_qty_global'] < 0) {
     form_set_error('uc_restrict_qty_global', t('You must enter 0 or a positive number value.'));
   }
+  if (!is_numeric($form_state['values']['uc_restrict_qty_default_qty']) || $form_state['values']['uc_restrict_qty_default_qty'] < 0) {
+    form_set_error('uc_restrict_qty_default_qty', t('You must enter 0 or a positive number value.'));
+  }
 }
 
 // Builds the form to display for adding or editing a the restricted quantity feature.
@@ -61,10 +84,11 @@
   $models = uc_product_get_models($node);
   if (!empty($feature)) {
     $product_qty = db_fetch_object(db_query("SELECT * FROM {uc_restrict_qty_products} WHERE pfid = %d", $feature['pfid']));
-    
+
     $default_qty = $product_qty->qty;
     $default_model = $product_qty->model;
-    
+    $default_lifetime = $product_qty->lifetime;
+
     $form['pfid'] = array(
       '#type' => 'value',
       '#value' => $feature['pfid'],
@@ -74,10 +98,6 @@
       '#value' => $product_qty->rqpid,
     );
   }
-  else {
-    $default_model = 0;
-    $default_qty = variable_get('uc_restrict_qty_default_qty', '1');
-  }
 /*  if ($result = db_result(db_query("SELECT COUNT(*) FROM {uc_product_features} WHERE nid = %d AND fid = '%s'", $node->nid, 'restrict_qty'))) {
     drupal_set_message(t('Adding more than one Restrict Qty. does nothing for now.', 'error'));
     $form['no_roles'] = array(
@@ -95,7 +115,7 @@
   $form['model'] = array(
     '#type' => 'select',
     '#title' => t('SKU'),
-    '#default_value' => $default_model,
+    '#default_value' => isset($default_model) ? $default_model : 0,
     '#description' => t('This is the SKU of the product that will be restricted to this quantity.'),
     '#options' => $models,
   );
@@ -105,14 +125,19 @@
     '#size' => 5,
     '#maxlength' => 5,
     '#description' => t('The number of times this product can be added to a cart. Set to 0 for unlimited.'),
-    '#default_value' => $default_qty,
+    '#default_value' => isset($default_qty) ? $default_qty : variable_get('uc_restrict_qty_default_qty', 0),
+  );
+  $form['lifetime'] = array(
+    '#title' => t('Is it a lifetime restriction?'),
+    '#type' => 'checkbox',
+    '#description' => t("If checked, user's ordering history will be taken into account too. Useful when you want to prevent double ordering of a product."),
+    '#default_value' => isset($default_lifetime) ? $default_lifetime : variable_get('uc_restrict_qty_default_lifetime', TRUE),
   );
   return uc_product_feature_form($form);
 }
 
 // Validates the textfield on the product features settings form.
 function uc_restrict_qty_feature_form_validate($form, &$form_state) {
-  
   // Invalid quantity?
   if (!is_numeric($form_state['values']['quantity']) || $form_state['values']['quantity'] < 0) {
     form_set_error('uc_restrict_qty_product_qty', t('You must enter 0 or a positive integer value.'));
@@ -134,11 +159,13 @@
     'nid'         => $form_state['values']['nid'],
     'model'       => $form_state['values']['model'],
     'qty'         => $form_state['values']['quantity'],
+    'lifetime'    => $form_state['values']['lifetime'],
   );
   
-  $description = empty($product_qty['model']) ? t('<strong>SKU:</strong> Any<br/>') : t('<strong>SKU:</strong> !sku<br/>', array('!sku' => $product_qty['model']));
-  $description .=  t('<strong>Quantity restriction:</strong> !qty<br/>', array('!qty' => $form_state['values']['quantity']));
-  
+  $description = '<strong>'. t('SKU') .':</strong> '. (empty($product_qty['model']) ? t('Any') : $product_qty['model']) .'<br/>';
+  $description .= '<strong>'. t('Quantity restriction') .':</strong> '. $product_qty['qty'] .'<br/>';
+  $description .= '<strong>'. t('Type'). ':</strong> '. ($product_qty['lifetime'] ? t('Lifetime') : t('Cart max.')) .'<br/>';
+
   $data = array(
     'pfid' => $product_qty['pfid'],
     'nid' => $product_qty['nid'],
@@ -166,12 +193,23 @@
  */
 function uc_restrict_qty_add_to_cart($nid, $qty, $data) {
   $limit = variable_get('uc_restrict_qty_global', 0);
-
   // If a global restriction on the number of items has been made.
   if ($limit > 0) {
     if (count(uc_cart_get_contents()) >= $limit) {
       $message = format_plural($limit, 'Sorry, you may only have 1 item in your cart. You must checkout or remove the item in your cart before adding a different item.',
-        'Sorry, you may only have a total of @count items in your cart.  You must checkout or remove items from your cart before adding others.');
+        'Sorry, you may only have a total of @count items in your cart. You must checkout or remove items from your cart before adding others.');
+
+      $result[] = array(
+        'success' => FALSE,
+        'message' => $message,
+      );
+    }
+  }
+
+  // Check lifetime product-level limit.
+  if ($data['restrict_qty']['lifetime']) {
+    if (!$data['restrict_qty']['rest']) {
+      $message = t('Sorry, you have reached the quantity limit for this product. You can not order more items of this product.');
 
       $result[] = array(
         'success' => FALSE,
@@ -195,11 +233,15 @@
 function uc_restrict_qty_cart_item($op, &$item) {
   if ($op == 'load') {
     // If this item has a quantity restriction on it...
-    if ($item->data['restrict_qty'] > 0 && $item->qty > $item->data['restrict_qty']) {
-      // Reduce the quantity to 1 if necessary.
-      db_query("UPDATE {uc_cart_products} SET qty = %d, changed = %d WHERE cart_id = '%s' AND nid = %d AND data = '%s'", $item->data['restrict_qty'], time(), uc_cart_get_id(), $item->nid, serialize($item->data));
-      $item->qty = $item->data['restrict_qty'];
-      drupal_set_message(t('You may only add !qty !item. to your cart. Quantity has been restricted.', array('!qty' => $item->qty, '!item' => $item->title)), 'warning');
+    if ($item->data['restrict_qty']['qty'] > 0) {
+      $is_lifetime = isset($item->data['restrict_qty']['lifetime']) && $item->data['restrict_qty']['lifetime'];
+      $restrict_qty = $is_lifetime ? $item->data['restrict_qty']['rest'] : $item->data['restrict_qty']['qty'];
+      if ($item->qty > $restrict_qty) {
+        // Reduce the quantity to 1 if necessary.
+        $item->qty = $restrict_qty;
+        db_query("UPDATE {uc_cart_products} SET qty = %d, changed = %d WHERE cart_id = '%s' AND nid = %d AND data = '%s'", $restrict_qty, time(), uc_cart_get_id(), $item->nid, serialize($item->data));
+        drupal_set_message(format_plural($restrict_qty, 'You may only add 1 !item to your cart. Quantity has been restricted.', 'You may only add @count !item to your cart. Quantity has been restricted.', array('!item' => $item->title)), 'warning');
+      }
     }
   }
 }
@@ -214,7 +256,9 @@
       $data = unserialize($form['items'][$i]['data']['#value']);
       
       // If this item has a quantity restriction on it...
-      if ($data['restrict_qty'] == 1) {
+      $is_lifetime = isset($data['restrict_qty']['lifetime']) && $data['restrict_qty']['lifetime'];
+      $restrict_qty = $is_lifetime ? $data['restrict_qty']['rest'] : $data['restrict_qty']['qty'];
+      if ($restrict_qty == 1) {
         $form['items'][$i]['qty']['#type'] = 'value';
         $form['items'][$i]['qty']['#theme'] = 'restrict_qty_field';
       }
@@ -233,7 +277,15 @@
 
 // Returns the number of restrict_qty features on a product node.
 function uc_restrict_qty_count($form_values) {
-  return db_result(db_query("SELECT qty FROM {uc_restrict_qty_products} WHERE nid = %d", $form_values['nid']));
+  global $user;
+
+  $data = db_fetch_array(db_query("SELECT qty, lifetime FROM {uc_restrict_qty_products} WHERE nid = %d", $form_values['nid']));
+  if ($data['lifetime']) {
+    $bought_qty = db_result(db_query('SELECT SUM(uop.qty) FROM {uc_orders} uo LEFT JOIN {uc_order_products} uop ON uo.order_id = uop.order_id WHERE uo.order_status = "completed" AND uo.uid = %d AND uop.nid = %d ORDER BY uop.nid', $user->uid, $form_values['nid']));
+    $data['rest'] = $data['qty'] - $bought_qty;
+  }
+
+  return $data;
 }
 
 /* ************************************************************************* *
--- translations/ajax_comments.pot
+++ translations/ajax_comments.pot
@@ -0,0 +1,169 @@
+# $Id$
+#
+# LANGUAGE translation of Drupal (general)
+# Copyright YEAR NAME <EMAIL@ADDRESS>
+# Generated from files:
+#  uc_restrict_qty.module,v 1.1.4.5.2.2 2009/04/13 11:21:15 mrfelton
+#  uc_restrict_qty.install,v 1.1.2.2 2009/05/11 17:28:55 mrfelton
+#  uc_restrict_qty.info,v 1.1.4.2 2008/10/17 14:41:03 mrfelton
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"POT-Creation-Date: 2009-05-13 19:11+0000\n"
+"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
+"Last-Translator: NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: uc_restrict_qty.module:28
+msgid "Restrict Qty"
+msgstr ""
+
+#: uc_restrict_qty.module:38
+msgid "This feature is limited in scope to preventing a user from adding different products to the cart.  This does not restrict the quantity of products in the cart if updated after being added, so this feature is best used on sites where all products have a restrict quantity feature on them."
+msgstr ""
+
+#: uc_restrict_qty.module:41
+msgid "Global limit"
+msgstr ""
+
+#: uc_restrict_qty.module:45
+msgid "The number of different products that can be added to a cart. Set to 0 for unlimited."
+msgstr ""
+
+#: uc_restrict_qty.module:50
+msgid "Defaults"
+msgstr ""
+
+#: uc_restrict_qty.module:52
+msgid "These options will take action, only if product has the \"Restrict quantity\" feature activated."
+msgstr ""
+
+#: uc_restrict_qty.module:55
+msgid "Default maximum limit for a product"
+msgstr ""
+
+#: uc_restrict_qty.module:59
+msgid "The number of products of single type that can be added to a cart. Set to 0 for unlimited."
+msgstr ""
+
+#: uc_restrict_qty.module:63
+msgid "Is restriction is the user's lifetime limit"
+msgstr ""
+
+#: uc_restrict_qty.module:65
+msgid "Useful when you want to prevent double ordering of a product."
+msgstr ""
+
+#: uc_restrict_qty.module:75;78
+msgid "You must enter 0 or a positive number value."
+msgstr ""
+
+#: uc_restrict_qty.module:117;165
+msgid "SKU"
+msgstr ""
+
+#: uc_restrict_qty.module:119
+msgid "This is the SKU of the product that will be restricted to this quantity."
+msgstr ""
+
+#: uc_restrict_qty.module:123
+msgid "Quantity limit"
+msgstr ""
+
+#: uc_restrict_qty.module:127
+msgid "The number of times this product can be added to a cart. Set to 0 for unlimited."
+msgstr ""
+
+#: uc_restrict_qty.module:131
+msgid "Is it a lifetime restriction?"
+msgstr ""
+
+#: uc_restrict_qty.module:133
+msgid "If checked, user's ordering history will be taken into account too. Useful when you want to prevent double ordering of a product."
+msgstr ""
+
+#: uc_restrict_qty.module:143
+msgid "You must enter 0 or a positive integer value."
+msgstr ""
+
+#: uc_restrict_qty.module:148
+msgid "A quantity restriction has already been set up for this SKU"
+msgstr ""
+
+#: uc_restrict_qty.module:165
+msgid "Any"
+msgstr ""
+
+#: uc_restrict_qty.module:166
+msgid "Quantity restriction"
+msgstr ""
+
+#: uc_restrict_qty.module:167
+msgid "Type"
+msgstr ""
+
+#: uc_restrict_qty.module:167
+msgid "Lifetime"
+msgstr ""
+
+#: uc_restrict_qty.module:167
+msgid "Cart max."
+msgstr ""
+
+#: uc_restrict_qty.module:212
+msgid "Sorry, you have reached the quantity limit for this product. You can not order more items of this product."
+msgstr ""
+
+#: uc_restrict_qty.module:199
+msgid "Sorry, you may only have 1 item in your cart. You must checkout or remove the item in your cart before adding a different item."
+msgid_plural "Sorry, you may only have a total of @count items in your cart. You must checkout or remove items from your cart before adding others."
+msgstr[0] ""
+msgstr[1] ""
+
+#: uc_restrict_qty.module:243
+msgid "You may only add 1 !item to your cart. Quantity has been restricted."
+msgid_plural "You may only add @count !item to your cart. Quantity has been restricted."
+msgstr[0] ""
+msgstr[1] ""
+
+#: uc_restrict_qty.module:0
+msgid "uc_restrict_qty"
+msgstr ""
+
+#: uc_restrict_qty.install:24
+msgid "The ID of the product feature this is attached to."
+msgstr ""
+
+#: uc_restrict_qty.install:31
+msgid "The ID of the node this role feature is attached to."
+msgstr ""
+
+#: uc_restrict_qty.install:38
+msgid "The product model."
+msgstr ""
+
+#: uc_restrict_qty.install:44
+msgid "The quantity restriction."
+msgstr ""
+
+#: uc_restrict_qty.install:51
+msgid "Is restriction lifetime?"
+msgstr ""
+
+#: uc_restrict_qty.info:0
+msgid "UC Restrict Qty"
+msgstr ""
+
+#: uc_restrict_qty.info:0
+msgid "Restrict the quantity on specified products so that only specified quantity may be purchased at a time."
+msgstr ""
+
+#: uc_restrict_qty.info:0
+msgid "Ubercart - extra"
+msgstr ""

--- uc_restrict_qty.test
+++ uc_restrict_qty.test
@@ -0,0 +1,309 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * UC Restrict Qty auto-tests.
+ */
+
+class UCRestrictQtyFunctionalTest extends DrupalWebTestCase {
+  function getInfo() {
+    return array(
+      'name'  => t('Various functional tests'),
+      'description'  => '',
+      'group' => t('UC Restrict Qty Tests'),
+    );
+  }
+  /**
+   * Implementation of setUp().
+   */
+  function setUp() {
+    parent::setUp('uc_store', 'uc_cart', 'uc_product', 'uc_order', 'ca', 'uc_restrict_qty');
+  }
+
+  /**
+   * Implementation of tearDown().
+   */
+  function tearDown() {
+    parent::tearDown();
+  }
+
+  function drupalCreateProduct($price = 100) {
+    // Create a product
+    $node = array(
+      'type' => 'product',
+      'sell_price' => $price,
+      'list_price' => '',
+      'cost' => '',
+      'model' => '',
+      'weight' => '',
+      'weight_units' => '',
+      'length' => '',
+      'width' => '',
+      'height' => '',
+      'length_units' => '',
+      'default_qty' => '',
+      'pkg_qty' => '',
+      'shippable' => 0,
+      'ordering' => '',
+    );
+    $product = $this->drupalCreateNode($node);
+    return $product;
+  }
+
+  function drupalCreateOrder($products = array(), $user = NULL) {
+    if (!isset($user)) {
+      $user = $this->drupalCreateUser();
+    }
+
+    $order = uc_order_new($user->uid);
+    if (!empty($products)) {
+      foreach ($products as $product) {
+        $product_data->order_product_id = 0;
+        $product_data->nid = $product->nid;
+        $product_data->qty = 1;
+        $product_data->title = $product->title;
+        $product_data->model = $product->model;
+        $product_data->cost = $product->cost;
+        $product_data->price = $product->sell_price;
+        $order->products[] = $product_data;
+      }
+    }
+
+    $order->delivery_first_name = $this->randomName();
+    $order->delivery_last_name = $this->randomName();
+    $order->delivery_phone = $this->randomName();
+    $order->delivery_company = $this->randomName();
+    $order->delivery_street1 = $this->randomName();
+    $order->delivery_street2 = $this->randomName();
+    $order->delivery_city = $this->randomName();
+    $order->delivery_zone = $this->randomName();
+    $order->delivery_postal_code = $this->randomName();
+    $order->delivery_country = $this->randomName();
+    $order->billing_first_name = $this->randomName();
+    $order->billing_last_name = $this->randomName();
+    $order->billing_phone = $this->randomName();
+    $order->billing_company = $this->randomName();
+    $order->billing_street1 = $this->randomName();
+    $order->billing_street2 = $this->randomName();
+    $order->billing_city = $this->randomName();
+    $order->billing_zone = $this->randomName();
+    $order->billing_postal_code = $this->randomName();
+    $order->billing_country = $this->randomName();
+    $order->payment_method = $this->randomName();
+    $order->manufacturer = $this->randomName();
+    $order->weight = rand();
+    $order->data = array();
+
+    uc_order_save($order);
+    return $order;
+  }
+
+  function testAdminProductSettings() {
+    $admin = $this->drupalCreateUser(array('administer product features'));
+    $this->drupalLogin($admin);
+
+    // Test settings' validators
+    $settings = array(
+      'uc_restrict_qty_global' => 'test',
+      'uc_restrict_qty_default_qty' => 1,
+      'uc_restrict_qty_default_lifetime' => 1,
+    );
+    $this->drupalPost('admin/store/settings/products/edit/features', $settings, t('Save configuration'));
+    $this->assertText(t('You must enter 0 or a positive number value.'), 'Settings validation [Global limit]');
+
+    $settings = array(
+      'uc_restrict_qty_global' => 1,
+      'uc_restrict_qty_default_qty' => 'test',
+      'uc_restrict_qty_default_lifetime' => 1,
+    );
+    $this->drupalPost('admin/store/settings/products/edit/features', $settings, t('Save configuration'));
+    $this->assertText(t('You must enter 0 or a positive number value.'), 'Settings validation [Default maximum limit for a product]');
+
+    // Submit real data
+    $settings = array(
+      'uc_restrict_qty_global' => 5,
+      'uc_restrict_qty_default_qty' => 2,
+      'uc_restrict_qty_default_lifetime' => 1,
+    );
+    $this->drupalPost('admin/store/settings/products/edit/features', $settings, t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), 'Settings saved');
+
+    $product = $this->drupalCreateProduct();
+
+    // Check if feature available
+    $this->drupalGet('node/'. $product->nid .'/edit/features');
+    $this->assertRaw('<option value="restrict_qty">'. t('Restrict Qty') .'</option>', 'Check if feature ready to be added');
+
+    // Test feature form default values
+    $test = array('feature' => 'restrict_qty');
+    $this->drupalPost('node/'. $product->nid .'/edit/features', $test, t('Add'));
+    $this->assertRaw('<input type="text" maxlength="5" name="quantity" id="edit-quantity" size="5" value="'. $settings['uc_restrict_qty_default_qty'] .'" class="form-text" />', 'Check if defaults prefilled [qty]');
+    $this->assertRaw('<input type="checkbox" name="lifetime" id="edit-lifetime" value="1"  checked="checked"  class="form-checkbox" />', 'Check if defaults prefilled [lifetime]');
+
+    // Test feature form submision
+    $product_settings = array(
+      'model'       => $product->model,
+      'quantity'    => 'test',
+      'lifetime'    => 1,
+    );
+    $this->drupalPost('node/'. $product->nid .'/edit/features/restrict_qty/add', $product_settings, t('Save feature'));
+    $this->assertText(t('You must enter 0 or a positive integer value.'), 'New product feature [validation]');
+    
+    // Save proper data
+    $product_settings['quantity'] = 1;
+    $this->drupalPost('node/'. $product->nid .'/edit/features/restrict_qty/add', $product_settings, t('Save feature'));
+    $this->assertText(t('The product feature has been added.'), 'New product feature [save|success message]');
+    $this->assertRaw('<td nowrap="nowrap">Restrict Qty</td>', 'New product feature [save|appeared in the table]');
+
+    // Double SKU submit check
+    $this->drupalPost('node/'. $product->nid .'/edit/features/restrict_qty/add', $product_settings, t('Save feature'));
+    $this->assertText(t('A quantity restriction has already been set up for this SKU'), 'New product feature [validation SKU]');
+    
+   $this->drupalGet('node/'. $product->nid .'/edit/features');
+   if (preg_match('|node/[0-9]*/edit/features/restrict_qty/[0-9]*|', $this->content, $matches)) {
+      $edit_url = $matches[0];
+      $this->drupalGet($edit_url);
+      $this->assertRaw('<input type="text" maxlength="5" name="quantity" id="edit-quantity" size="5" value="'. $product_settings['quantity'] .'" class="form-text" />', 'Check if new data saved [qty]');
+      $this->assertRaw('<input type="checkbox" name="lifetime" id="edit-lifetime" value="1"  checked="checked"  class="form-checkbox" />', 'Check if new data saved [lifetime]');
+
+      // Test feature form updation
+      $product_settings = array(
+        'model'       => $product->model,
+        'quantity'    => 55,
+        'lifetime'    => FALSE,
+      );
+      $this->drupalPost($edit_url, $product_settings, t('Save feature'));
+      $this->assertText(t('The product feature has been updated.'), 'Feature updated');
+      $this->drupalGet($edit_url);
+      $this->assertRaw('<input type="text" maxlength="5" name="quantity" id="edit-quantity" size="5" value="'. $product_settings['quantity'] .'" class="form-text" />', 'Check if updated data saved [qty]');
+      $this->assertRaw('<input type="checkbox" name="lifetime" id="edit-lifetime" value="1"   class="form-checkbox" />', 'Check if updated data saved [lifetime]');
+    }
+    else {
+      $this->fail('Feature edit link not found');
+    }
+  }
+
+  function testGlobalLimit() {
+    $limit = 2;
+    variable_set('uc_restrict_qty_global', $limit);
+    $product = $this->drupalCreateProduct();
+    $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+    $this->assertRaw(t('<strong>@product-title</strong> added to <a href="!url">your shopping cart</a>.', array('@product-title' => $product->title, '!url' => url('cart'))), 'Global limit [adding to cart below limit]');
+
+    $product = $this->drupalCreateProduct();
+    $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+    $this->assertRaw(t('<strong>@product-title</strong> added to <a href="!url">your shopping cart</a>.', array('@product-title' => $product->title, '!url' => url('cart'))), 'Global limit [close to limit]');
+
+    $product = $this->drupalCreateProduct();
+    $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+    $this->assertNoRaw(t('<strong>@product-title</strong> added to <a href="!url">your shopping cart</a>.', array('@product-title' => $product->title, '!url' => url('cart'))), 'Global limit [above the limit|not added]');
+    $this->assertRaw(format_plural($limit, 'Sorry, you may only have 1 item in your cart. You must checkout or remove the item in your cart before adding a different item.',
+        'Sorry, you may only have a total of @count items in your cart. You must checkout or remove items from your cart before adding others.'), 'Global limit [above the limit|message shown]');
+
+    variable_set('uc_restrict_qty_global', 0);
+    $product = $this->drupalCreateProduct();
+    $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+    $this->assertRaw(t('<strong>@product-title</strong> added to <a href="!url">your shopping cart</a>.', array('@product-title' => $product->title, '!url' => url('cart'))), 'Global limit [no limit]');
+  }
+
+  function testProductLimit() {
+    $admin = $this->drupalCreateUser(array('administer product features'));
+    $this->drupalLogin($admin);
+
+    $product = $this->drupalCreateProduct();
+    variable_set('uc_restrict_qty_global', 0);
+    $product_settings = array(
+      'model'       => $product->model,
+      'quantity'    => 1,
+      'lifetime'    => 0,
+    );
+    $this->drupalPost('node/'. $product->nid .'/edit/features/restrict_qty/add', $product_settings, t('Save feature'));
+
+    $user1 = $this->drupalCreateUser();
+    $this->drupalLogin($user1);
+
+    $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+    $this->assertRaw(t('<strong>@product-title</strong> added to <a href="!url">your shopping cart</a>.', array('@product-title' => $product->title, '!url' => url('cart'))), 'Product limit [#1 to add]');
+
+    // Single item should be not included into input field
+    $this->assertRaw('<td class="qty">1</td>', 'Global limit [#1 without input in cart]');
+
+    // Second should cause error
+    $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+    $this->assertRaw(format_plural($product_settings['quantity'], 'You may only add 1 !item to your cart. Quantity has been restricted.', 'You may only add @count !item to your cart. Quantity has been restricted.', array('!item' => $product->title)), 'Product limit [above the limit]');
+
+    $this->drupalLogin($admin);
+    $this->drupalGet('node/'. $product->nid .'/edit/features');
+    if (preg_match('|node/[0-9]*/edit/features/restrict_qty/[0-9]*|', $this->content, $matches)) {
+      $edit_url = $matches[0];
+      $product_settings = array(
+        'model'       => $product->model,
+        'quantity'    => 2,
+        'lifetime'    => FALSE,
+      );
+      $this->drupalPost($edit_url, $product_settings, t('Save feature'));
+
+      // Login another user (to get empty cart)
+      $user2 = $this->drupalCreateUser();
+      $this->drupalLogin($user2);
+
+      $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+      $this->assertRaw(t('<strong>@product-title</strong> added to <a href="!url">your shopping cart</a>.', array('@product-title' => $product->title, '!url' => url('cart'))), 'Product limit [#2 to add|first]');
+
+      // Item should be included into input field
+      $this->assertRaw('<input type="text" maxlength="6" name="items[0][qty]" id="edit-items-0-qty" size="5" value="1" class="form-text" />', 'Product limit [#2 with input in cart]');
+
+      $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+      $this->assertRaw(t('Your item(s) have been updated.'), '#2 to add|second');
+      $this->assertNoRaw(format_plural($product_settings['quantity'], 'You may only add 1 !item to your cart. Quantity has been restricted.', 'You may only add @count !item to your cart. Quantity has been restricted.', array('!item' => $product->title)), 'Product limit [#2 to add|second|no warnings]');
+
+      $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+      $this->assertRaw(format_plural($product_settings['quantity'], 'You may only add 1 !item to your cart. Quantity has been restricted.', 'You may only add @count !item to your cart. Quantity has been restricted.', array('!item' => $product->title)), 'Product limit [#2 to add|third|above limit warning]');
+      $this->assertRaw('<input type="text" maxlength="6" name="items[0][qty]" id="edit-items-0-qty" size="5" value="2" class="form-text" />', 'Product limit [#2 to add|third|#2 in cart]');
+
+      // Test lifetime limit
+      $this->drupalLogin($admin);
+      $product_settings = array(
+        'model'       => $product->model,
+        'quantity'    => 2,
+        'lifetime'    => 1,
+      );
+      $this->drupalPost($edit_url, $product_settings, t('Save feature'));
+
+      $user3 = $this->drupalCreateUser(array('view own orders'));
+      $this->drupalLogin($user3);
+      
+      $products = array($product);
+      $order = $this->drupalCreateOrder($products, $user3);
+      uc_order_update_status($order->order_id, 'completed');
+
+      $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+      $this->assertRaw(t('<strong>@product-title</strong> added to <a href="!url">your shopping cart</a>.', array('@product-title' => $product->title, '!url' => url('cart'))), 'Product lifetime limit [first and last]');
+
+      // It should be single item without input, as we have limit 2 with one alrready ordered
+      $this->assertRaw('<td class="qty">1</td>', 'Product lifetime limit [#1 without input in cart]');
+
+      // Second should cause error
+      $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+      $this->assertRaw(format_plural($product_settings['quantity'] - count($products), 'You may only add 1 !item to your cart. Quantity has been restricted.', 'You may only add @count !item to your cart. Quantity has been restricted.', array('!item' => $product->title)), 'Product lifetime limit [above the limit]');
+
+      // Restrict adding product to the cart, if limit has been reached
+      $this->drupalLogin($admin);
+      $product_settings = array(
+        'model'       => $product->model,
+        'quantity'    => 1,
+        'lifetime'    => 1,
+      );
+      $this->drupalPost($edit_url, $product_settings, t('Save feature'));
+      $this->drupalLogin($user3);
+
+      // Any adding to cart should cause warning, as everything available already ordered
+      $this->drupalPost('node/'. $product->nid, array(), t('Add to cart'));
+      $this->assertRaw(t('Sorry, you have reached the quantity limit for this product. You can not order more items of this product.'), 'Product lifetime limit [above the limit]');
+    }
+    else {
+      $this->fail('Feature edit link not found');
+    }
+  }
+}


