1

I am trying to limit a user's total quantity of products across their entire order/purchase history based on a field on that product. For example, if Can of Peanuts has a limit of 3 per user, then the user should not be able to buy 3 then place another order for 3.

Does anyone have any recommendations for ways to accomplish this?

2

Use hook_form_commerce_cart_add_to_cart_form_alter()

<?php 
mymodule_form_commerce_cart_add_to_cart_form_alter(&$form, &$form_state, $form_id)
{ 
  /*code*/ 
}
?>

Then, inside the hook, use entityFieldQuery to get list of orders for this user

For locating the "currently selected product," you can use the form_state variable:

<?php 
$current_product = $form_state['default_product']; 
?>

Finally, you'll want to iterate over each order and use entity meta data wrappers to wrap the orders so you can iterate over the line items, looking for matching products.

<?php
foreach ($orders as $order_id => $order) {
  $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
  foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
    $line_item = $line_item_wrapper->value();
  }
}
?>

The final final round would include looking to see if the line item is attached to the product and then counting the number of products this person has purchased.

Unfortunately, while you might be able to construct an SQL statement that does most of the heavy lifting (instead of iterating over all the user's orders and line items), it would require much more intimate knowledge of your particular store architecture.

0

You can create a conditional rule to count the products in the cart, then create an action to remove Commerce Line Item from the cart if certain limit is reached.

Here is the example code:

/**
 * Implements hook_rules_condition_info().
 */
function foo_webstore_rules_condition_info() {
  return array(
    'foo_webstore_rules_condition_ordered_num_line_items' => array(
      'group' => t('Commerce'),
      'callbacks' => array(
        'execute' => 'foo_webstore_rules_condition_ordered_num_line_items',
      ),
      'label' => t('User ordered number of line items'),
      'parameter' => array(
        'count_type' => array(
          'type' => 'text',
          'label' => t('Products to compare'),
          'description' => t('Select which products should be taken into consideration.'),
          'optional' => TRUE,
          'default value' => '=',
          'options list' => 'foo_webstore_rules_condition_ordered_num_line_items_count_types',
          'restriction' => 'input',
        ),
        'commerce_line_item' => array(
          'type' => 'commerce_line_item',
          'label' => t('Product')
        ),
        'operator' => array(
          'type' => 'text',
          'label' => t('Operator'),
          'description' => t('The comparison operator.'),
          'optional' => TRUE,
          'default value' => '=',
          'options list' => 'commerce_numeric_comparison_operator_options_list',
          'restriction' => 'input',
        ),
        'value' => array(
          'type' => 'text',
          'label' => t('Value'),
          'description' => t('Integer representing a value.'),
          'default value' => '0',
        ),
      ),
      'module' => 'foo_webstore',
    ),
  );
}

/**
 * Rules condition's select box items for "Products to compare".
 */
function foo_webstore_rules_condition_ordered_num_line_items_count_types() {
  return array(
    'any' => t('Count products of any type'),
    'any|free' => t('Count free products of any type'),
    'exact' => t('Count products of the same type'),
    'exact|free' => t('Count free products of the same type'),
  );
}

/**
 * Rules action callback for "User ordered number of line items".
 */
function foo_webstore_rules_condition_ordered_num_line_items($count_type, $line_item, $operator, $value) {
  $count_types = explode('|', $count_type);

  $num_in_cart  = 0;
  $product_id   = $line_item->data['context']['entity']['entity_id'];
  $line_item_id = $line_item->line_item_id;
  $product_id   = reset($line_item->data['context']['product_ids']);

  // Checking total number of products in the cart.
  $cart_order = commerce_cart_order_load($GLOBALS['user']->uid);

  foreach ($cart_order->commerce_line_items[LANGUAGE_NONE] as $item) {
    $cart_line_item = commerce_line_item_load($item['line_item_id']);
    $cart_product_id = reset($cart_line_item->data['context']['product_ids']);
    $cart_product_price_free = $cart_line_item->commerce_total[LANGUAGE_NONE][0]['amount'] == 0;

    if (in_array('any', $count_types) || (in_array('exact', $count_types) && $cart_product_id === $product_id)) {
      if (!in_array('free', $count_types) || $cart_product_price_free) {
        ++$num_in_cart;
      }
    }
  }

  $num_bought = 0;

  // Checking how many products of this is user already bought.
  $data = db_query("
    SELECT LI.line_item_id AS lid, LI.quantity, LI.data
    FROM commerce_order O
    LEFT JOIN commerce_line_item LI ON LI.order_id = O.order_id
    WHERE O.`status` NOT IN ('selected', 'cart', 'canceled') AND O.uid = :uid
  ", array(
    ':uid' => $GLOBALS['user']->uid
  ))->fetchAll();

  foreach ($data as $row) {
    $commerce_data = unserialize ($row->data);
    $bought_product_id = reset($commerce_data['context']['product_ids']);

    // @TODO: Would be a good idea to check price in another way if we want code to be shareable.
    $bought_product = commerce_product_load($bought_product_id);

    $bought_product_price_free = $bought_product->commerce_price_eur[LANGUAGE_NONE][0]['amount'] == 0;

    if (in_array('any', $count_types) || (in_array('exact', $count_types) && $bought_product_id === $product_id)) {
      if (!in_array('free', $count_types) || $bought_product_price_free) {
        ++$num_bought;
      }
    }
  }

  // "1" is for current line item.
  $num_total = $num_in_cart + $num_bought + 1;

  switch ($operator) {
    case '<':  return $num_total <  $value;
    case '<=': return $num_total <= $value;
    case '=':  return $num_total == $value;
    case '>=': return $num_total >= $value;
    case '>':  return $num_total >  $value;
  }
}

function foo_webstore_rules_action_info() {
  return array(
    'foo_webstore_remove_line_item_from_cart_action' => array(
      'group' => t('Commerce'),
      'label' => t('Remove line item from the cart'),
      'parameter' => array(
        'commerce_line_item' => array(
          'type' => 'commerce_line_item',
          'label' => t('Commerce Line Item'),
        ),
      ),
    ),
  );
}

/**
 * Rules action. Removes Commerce Line Item from the cart.
 */
function foo_webstore_remove_line_item_from_cart_action($commerce_line_item) {
  commerce_line_item_delete($commerce_line_item->line_item_id);
}

Related Drupal posts: #2189247, #1267156.

See also: Limit Quantity When Adding a Product to Cart.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.