Discussions

Restrict Qty

I'm trying to accomplish something similar to the functionality of Ryan's UC Restrict Qty module.

We have a site that will be selling digital downloads, and we don't want customers accidentally ordering more than one of any product (it would be a waste of their money, and we'd probably have to find a way to offer refunds etc).

I'm guessing there's probably a way to accomplish this with rules, but so far I've been unsuccessful. Any ideas?

Posted: Jul 24, 2011

Comments

zeta1600 on August 5, 2011

I hope this helps someone. This allows users to "0" quantity and remove the item, as well as disallow any number higher than quantity of "1"

Create a new rule: Name it
Event: After updating an existing commerce line item
Add Action: Set a data value
-- Data Selector: commerce-line-item:quantity
-- Value: 1

dwkitchen David Kitchen on September 2, 2011

I have set up both of these rules as I only want customers to be able to buy one ticket but neither seem to work.

As a test I set the add to cart event to remove all other items from the cart and that works for anon users but not the admin.

Any ideas why not?

I am also trying to figure out a rule that if the cart already has a product of type ticket in it, the user cannot add another ticket. I think I am going to need a loop?

David

Rich Edwards on October 18, 2012

I am real new to Drupal, but have set rules and events for relating to a specific model (commerce flat rate). I really need to restrict this quantity also. Where Do I get access to this event? I am running Drupal 7 commerce kick start. Thanks!

Rich Edwards on October 19, 2012

I am new to Drupal. I am running on Drupal 7 with commerce kickstart as a base. If you could point me to documentation on how to do this I would appreciate it. I understand the solution but don't know how to find the event "After adding item to cart".

davidwhthomas on September 21, 2011

In accordance with the business rules, I used the following Drupal rule to restrict the cart to the single latest product a user has added only:

"Before adding a product to the cart" > IF "Total product quantity comparison" >=1 > "Remove all products from an order"

This rule basically removes the old product and adds the new one, if a product is added twice.

Export code:

{ "rules_restrict_to_single_product" : {
"LABEL" : "Restrict to single product",
"PLUGIN" : "reaction rule",
"REQUIRES" : [ "commerce_order", "commerce_cart", "rules" ],
"ON" : [ "commerce_cart_product_prepare" ],
"IF" : [
{ "commerce_order_compare_total_product_quantity" : {
"commerce_order" : [ "commerce_order" ],
"operator" : "\u003e=",
"value" : "1"
}
}
],
"DO" : [
{ "commerce_cart_empty" : { "commerce_order" : [ "commerce_order" ] } }
]
}
}

I hope that helps someone else.

nic on January 15, 2013

Almost perfect... Just missing to check if the order is completed:

{ "rules_restrict_to_single_product" : {
    "LABEL" : "Restrict to single product",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [ "commerce_order", "rules", "commerce_cart" ],
    "ON" : [ "commerce_cart_product_prepare" ],
    "IF" : [
      { "commerce_order_compare_total_product_quantity" : {
          "commerce_order" : [ "commerce_order" ],
          "operator" : "\u003E=",
          "value" : "1"
        }
      },
      { "NOT data_is" : { "data" : [ "commerce-order:state" ], "value" : "completed" } }
    ],
    "DO" : [
      { "commerce_cart_empty" : { "commerce_order" : [ "commerce_order" ] } }
    ]
  }
}

agileadam on March 28, 2012

Here's how I've made sure users can only click the "add to cart" button on items that aren't already in their cart. On this site, we also only want to allow a quantity of 1 on all "program" items. Please let me know if I'm doing something wrong here... but it seems to be working great.

The input filter's markdown support is seriously breaking my comment syntax... I wish I knew how to fix this problem.
For now, a cleaner version of this code is here: http://drupalbin.com/21095

<?php
/**
 * Implements hook_form_FORMID_alter().
 */
function mymodule_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state) {
 
$product_ids = mymodule_get_products_in_cart();

 
$line_item = $form_state['line_item'];
 
$product = commerce_product_load($line_item->commerce_product[LANGUAGE_NONE][0]['product_id']);
  if (
$product->type == 'program') {
    if (
in_array($product->product_id, $product_ids)) {
     
// Product is already in cart! We only want to allow a quantity of 1,
      // so disable the submit button and change its text accordingly
     
$form['submit']['#disabled'] = TRUE;
     
$form['submit']['#value'] = t('Already in cart');
    }
  }
}  
 
/**
 * Return the product_id values for all products in the cart
 *
 * @return
 *  An array of product ids
 */
function mymodule_get_products_in_cart() {
 
$product_ids = &drupal_static(__FUNCTION__);

  if (!isset(
$product_ids)) {
    global
$user;
   
$product_ids = array();
   
$order = commerce_cart_order_load($user->uid);
    if (
$order) {
     
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
      foreach (
$order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
       
$product_wrapper = $line_item_wrapper->commerce_product;
       
$product_ids[] = $product_wrapper->product_id->value();
      }
    }
  }

  return
array_unique($product_ids);
}
?>

JMOmandown on November 15, 2012

Instead of writing a custom module this is possible within rules out of the box. Plus rules is a better solution when you only want to restrict the quantity of a SINGLE product. Below is an example:

{ "rules_force_index_quantity_to_1" : {
    "LABEL" : "Force Index Quantity to 1",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [ "commerce_order", "rules", "entity" ],
    "ON" : [ "commerce_line_item_presave" ],
    "IF" : [
      { "commerce_order_contains_product" : {
          "commerce_order" : [ "commerce-line-item:order" ],
          "product_id" : "your_product_sku",
          "operator" : "\u003E=",
          "value" : "1"
        }
      },
      { "data_is" : { "data" : [ "commerce-line-item:type" ], "value" : "product" } },
      { "data_is" : {
          "data" : [ "commerce-line-item:commerce-product:sku" ],
          "value" : "your_product_sku"
        }
      }
    ],
    "DO" : [
      { "data_set" : { "data" : [ "commerce-line-item:quantity" ], "value" : "1" } },
      { "drupal_message" : {
          "message" : "This product has already been added to your cart and is limited to one per purchase",
          "type" : "warning",
          "repeat" : 0
        }
      }
    ]
  }
}

Channel Islander on January 22, 2015

Hi there,

This Rule works perfectly for forcing the line item quantity to 1 but it doesn't address the line item price.

So each time the user tries to change the quantity, the quantity is reset to 1 but the line item total is set to what it would be if the user's quantity change succeeded. So they get to checkout with a quantity of 1 but a price n times that.

Here is the Rule with another action to set the line item's total price to the line item product's unit price:

{ "rules_force_index_quantity_to_1" : {
"LABEL" : "Force Index Quantity to 1",
"PLUGIN" : "reaction rule",
"REQUIRES" : [ "commerce_order", "rules", "entity" ],
"ON" : [ "commerce_line_item_presave" ],
"IF" : [
{ "commerce_order_contains_product" : {
"commerce_order" : [ "commerce-line-item:order" ],
"product_id" : "your_product_sku",
"operator" : "\u003E=",
"value" : "1"
}
},
{ "data_is" : { "data" : [ "commerce-line-item:type" ], "value" : "product" } },
{ "data_is" : {
"data" : [ "commerce-line-item:commerce-product:sku" ],
"value" : "your_product_sku"
}
}
],
"DO" : [
{ "data_set" : { "data" : [ "commerce-line-item:quantity" ], "value" : "1" } },
{ "data_set" : {
"data" : [ "commerce-line-item:commerce-total" ],
"value" : [ "commerce-line-item:commerce-unit-price" ]
}
},
{ "drupal_message" : {
"message" : "This product has already been added to your cart and is limited to one per purchase",
"type" : "warning",
"repeat" : 0
}
}
]
}
}

Per Eriksson on April 25, 2015

Hi,

We tried a lot of different options. At the end the most stable and reliable solution was to reuse the commerce_stock rules, copy and modify them to act on a custom field that we added to the product (Max quantity). This way:
* You can restrict the quantity per product
* The checks are performed in the commerce_cart_form
* The quantity is checked with old carts when heading to checkout

We're thinking of creating a module for this. Just email if you want the rules export.

roelwelters on July 30, 2015

this is the rule we used,

{ "rules_limit_quantity_to_1" : {
"LABEL" : "Limit Quantity to 1",
"PLUGIN" : "reaction rule",
"OWNER" : "rules",
"TAGS" : [ "limited" ],
"REQUIRES" : [ "rules", "rules_i18n", "entity" ],
"ON" : { "commerce_line_item_presave" : [] },
"IF" : [
{ "entity_is_of_bundle" : {
"entity" : [ "commerce-line-item" ],
"type" : "commerce_line_item",
"bundle" : { "value" : { "product" : "product" } }
}
},
{ "data_is" : {
"data" : [ "commerce-line-item:commerce-product:sku" ],
"value" : "5010494924800"
}
}
],
"DO" : [
//set the line item value to 1
{ "data_set" : { "data" : [ "commerce-line-item:quantity" ], "value" : "1" } },
//display a message for the user
{ "drupal_message" : {
"message" : "This article is limited to 1 per person.",
"type" : "error",
"repeat" : "0"
}
},
// to prevent the total amount adding up you replace the total line item amount with the unit price
{ "data_set" : {
"data" : [ "commerce-line-item:commerce-total" ],
"value" : [ "commerce-line-item:commerce-unit-price" ] // to prevent the total amount adding up you replace the total line item amount with the unit price
}
}
]
}
}