Answers.Body: <p>Have you looked into building an adjuster for this purpose? You can find the documentation <a href="https://craftcommerce.com/docs/adjusters" rel="nofollow noreferrer">here</a></p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-11T13:07:52.863Z
Answers.Text: Hey Andris, thanks for the reply. I've built custom adjusters in the past, so it definitely wouldn't be an issue to get one incorporated. I'm just curious if that is the best way to go or something like using an `onPopulateLineItem` event. Maybe 6 of one, half dozen of another?
Answers.UserDisplayName: Peter Tell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-12T02:26:36.963Z
Answers.Text: Definitely recommend your own discount adjuster if you have advanced logic for reducing the price of line items. Make sure the adjuster class you return runs after the built in discount system to ensure it runs before tax and shipping adjusters.
Answers.UserDisplayName: Luke Holder
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-12T14:56:13.363Z
Answers.Text: Cool thanks Luke (and Andris) -- could you elaborate on why you would recommend the adjuster route vs `onPopuplateLineItem`?
Answers.UserDisplayName: Peter Tell
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-13T06:35:08.573Z
Answers.Text: @PeterTell `onPopulateLineItem` could also work fine, but you wouldn't be storing the discount calculation or description in an adjustment in the cart. You also could have other line items containing the same product, and `onPopulateLineItem` only cares about the qty of a single line item - an adjuster could look at the whole cart and see 2 line items both with the same product in them and add a single adjustment.
Answers.UserDisplayName: Luke Holder
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2017-09-10T08:37:31.703Z
Answers.LastActivityDate: 2017-09-10T08:37:31.703Z
Answers.UserDisplayName: Andris Sevcenko
Body: <p>I'm curious what the best way to handle quantity discounts would be on a product/variant level. For example:</p>
  
  <p>The base price of a <strong>variant</strong> is $3 each, but if you buy 10-19 they're $2 each, and if you buy more than 20 they're $1 each.</p>
  
  <p>A different variant of the same product could have a base price of $10 each, but if you buy 20-49 they're $8 each, and if you buy over 50 they're $6 each.</p>
  
  <p>Thoughts?</p>
  
  <p><strong>EDIT 2 (added file paths)</strong></p>
  
  <p>Based on the comments by Luke and Andris below, I've implemented an adjuster to handle this. I created a <code>table</code> field with the handle <code>quantityPricing</code> with 3 columns: <code>minQuantity</code>, <code>maxQuantity</code>, <code>price</code>. I then applied this field to the variants on a product.</p>
  
  <p>This way a user can create as many prices for quantity ranges as they want. I then create the adjuster, checking the line items via the following:</p>
  
  <p><code>craft/plugins/myplugin/Adjusters/Myplugin_Adjustername.php</code></p>
  
  <pre><code>&lt;?php
  
  namespace Commerce\Adjusters;
  use Craft\Commerce_LineItemModel;
  use Craft\Commerce_OrderAdjustmentModel;
  use Craft\Commerce_OrderModel;
  
  class Myplugin_Adjustername implements Commerce_AdjusterInterface {
  public function adjust(Commerce_OrderModel &amp;$order, array $lineItems = [])
  {
  
      if (empty($lineItems))
      {
          return [];
      }
  
      $updated  = [];
      $amount   = 0;
      $adjuster = new Commerce_OrderAdjustmentModel();
  
      $adjuster-&gt;type        = 'Discount';
      $adjuster-&gt;name        = 'Quantity Pricing';
      $adjuster-&gt;description = 'The overall price of the cart has been adjsuted based on the number of items you are purchasing.';
      $adjuster-&gt;orderId     = $order-&gt;id;
  
      foreach ($lineItems as $lineItem)
      {
          $purchasable = $lineItem-&gt;purchasable;
          if (!empty($purchasable-&gt;quantityPricing))
          {
              $updated[]     = $lineItem-&gt;id;
              $updatedAmount = 0;
              foreach ($purchasable-&gt;quantityPricing as $qp)
              {
                  if (
                      ($lineItem-&gt;qty &gt;= $qp['minQuantity'] &amp;&amp; $lineItem-&gt;qty &lt;= $qp['maxQuantity'])
                   ||
                      ($lineItem-&gt;qty &gt;= $qp['minQuantity'] &amp;&amp; empty($qp['maxQuantity']))
                  )
                  {
                      $lineItem-&gt;discount = ($qp['price'] - $lineItem-&gt;price) * $lineItem-&gt;qty;
                      $updatedAmount      = $lineItem-&gt;discount;
                  }
              }
              $amount += $updatedAmount;
          }
      }
  
      $adjuster-&gt;amount      = $amount;
      $adjuster-&gt;optionsJson = ['lineItemsAffected' =&gt; $updated];
  
      $adjuster-&gt;included = false;
  
      if (empty($updated))
      {
          return[];
      }
  
      return [$adjuster];
  }
  }
  </code></pre>
  
  <p>I was also seemingly able to do this using <code>onPopulateLineItem</code> but based on the advice below changed it. My code for that looked like this:</p>
  
  <pre><code>    craft()-&gt;on('commerce_lineItems.onPopulateLineItem', function($event){
  
              $purchasable = $event-&gt;params['purchasable'];
              $lineItem    = $event-&gt;params['lineItem'];
  
              // This method checks for quantity pricing and updates 
              // line items costs depending on what it finds.
              if (!empty($purchasable-&gt;quantityPricing))
              {
                  foreach ($purchasable-&gt;quantityPricing as $qp)
                  {
                      if (
                          ($lineItem-&gt;qty &gt;= $qp['minQuantity'] &amp;&amp; $lineItem-&gt;qty &lt;= $qp['maxQuantity'])
                       ||
                          ($lineItem-&gt;qty &gt;= $qp['minQuantity'] &amp;&amp; empty($qp['maxQuantity']))
                      )
                      {
                          $lineItem-&gt;price = (float) $qp['price'];
                      }
                  }
              }
          });
  </code></pre>
  
  <p>As mentioned in the comments below, I'm not exactly sure why an Adjuster is the better route to go, because both seem to work.</p>
  
  <p>Please don't hesitate to mention if I did something ridiculously stupid somewhere. It certainly wouldn't be the first time.</p>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2018-03-03T15:28:08.883Z
Comments.Text: Hi peter, that's exactly what I would need too. But I am very new to adjusters and plugins. Could you tell me exactly where to put this code and how the file is named? Of course only if you have the time...
Comments.UserDisplayName: outline4
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2018-03-23T21:08:10.797Z
Comments.Text: Hey @outline4 - Sorry for the delay! I updated my example with a full example of the Adjuster file plus the exact path to it from a hypothetical plugin.
Comments.UserDisplayName: Peter Tell
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2018-03-23T21:13:49.867Z
Comments.Text: Also, don't forget to register the adjuster: https://craftcms.stackexchange.com/questions/20327/craft-commerce-for-a-discount-can-we-include-all-products-in-the-product-coun/20404?noredirect=1#comment32858_20404
Comments.UserDisplayName: Peter Tell
Tags: <plugin-craftcommerce>
Title: Craft Commerce: How do I handle quantity based discounts on a product level?
ThreadText: # Craft Commerce: How do I handle quantity based discounts on a product level?
  
  (Asked by: username_0 on 2017-09-08)
  
  I'm curious what the best way to handle quantity discounts would be on a product/variant level. For example:
  
  The base price of a **variant** is $3 each, but if you buy 10-19 they're $2 each, and if you buy more than 20 they're $1 each.
  
  A different variant of the same product could have a base price of $10 each, but if you buy 20-49 they're $8 each, and if you buy over 50 they're $6 each.
  
  Thoughts?
  
  **EDIT 2 (added file paths)**
  
  Based on the comments by username_3 and username_2 below, I've implemented an adjuster to handle this. I created a `table` field with the handle `quantityPricing` with 3 columns: `minQuantity`, `maxQuantity`, `price`. I then applied this field to the variants on a product.
  
  This way a user can create as many prices for quantity ranges as they want. I then create the adjuster, checking the line items via the following:
  
  `craft/plugins/myplugin/Adjusters/Myplugin_Adjustername.php`
  
  ```
  <?php
  
  namespace Commerce\Adjusters;
  use Craft\Commerce_LineItemModel;
  use Craft\Commerce_OrderAdjustmentModel;
  use Craft\Commerce_OrderModel;
  
  class Myplugin_Adjustername implements Commerce_AdjusterInterface {
  public function adjust(Commerce_OrderModel &$order, array $lineItems = [])
  {
  
      if (empty($lineItems))
      {
          return [];
      }
  
      $updated  = [];
      $amount   = 0;
      $adjuster = new Commerce_OrderAdjustmentModel();
  
      $adjuster->type        = 'Discount';
      $adjuster->name        = 'Quantity Pricing';
      $adjuster->description = 'The overall price of the cart has been adjsuted based on the number of items you are purchasing.';
      $adjuster->orderId     = $order->id;
  
      foreach ($lineItems as $lineItem)
      {
          $purchasable = $lineItem->purchasable;
          if (!empty($purchasable->quantityPricing))
          {
              $updated[]     = $lineItem->id;
              $updatedAmount = 0;
              foreach ($purchasable->quantityPricing as $qp)
              {
                  if (
                      ($lineItem->qty >= $qp['minQuantity'] && $lineItem->qty <= $qp['maxQuantity'])
                   ||
                      ($lineItem->qty >= $qp['minQuantity'] && empty($qp['maxQuantity']))
                  )
                  {
                      $lineItem->discount = ($qp['price'] - $lineItem->price) * $lineItem->qty;
                      $updatedAmount      = $lineItem->discount;
                  }
              }
              $amount += $updatedAmount;
          }
      }
  
      $adjuster->amount      = $amount;
      $adjuster->optionsJson = ['lineItemsAffected' => $updated];
  
      $adjuster->included = false;
  
      if (empty($updated))
      {
          return[];
      }
  
      return [$adjuster];
  }
  }
  
  ```
  
  I was also seemingly able to do this using `onPopulateLineItem` but based on the advice below changed it. My code for that looked like this:
  
  ```
      craft()->on('commerce_lineItems.onPopulateLineItem', function($event){
  
              $purchasable = $event->params['purchasable'];
              $lineItem    = $event->params['lineItem'];
  
              // This method checks for quantity pricing and updates 
              // line items costs depending on what it finds.
              if (!empty($purchasable->quantityPricing))
              {
                  foreach ($purchasable->quantityPricing as $qp)
                  {
                      if (
                          ($lineItem->qty >= $qp['minQuantity'] && $lineItem->qty <= $qp['maxQuantity'])
                       ||
                          ($lineItem->qty >= $qp['minQuantity'] && empty($qp['maxQuantity']))
                      )
                      {
                          $lineItem->price = (float) $qp['price'];
                      }
                  }
              }
          });
  
  ```
  
  As mentioned in the comments below, I'm not exactly sure why an Adjuster is the better route to go, because both seem to work.
  
  Please don't hesitate to mention if I did something ridiculously stupid somewhere. It certainly wouldn't be the first time.
  
  **Tags:** plugin-craftcommerce
  
  > **Comments:**
  > **username_1**: Hi username_0, that's exactly what I would need too. But I am very new to adjusters and plugins. Could you username_0 me exactly where to put this code and how the file is named? Of course only if you have the time...  
  > **username_0**: Hey @username_1 - Sorry for the delay! I updated my example with a full example of the Adjuster file plus the exact path to it from a hypothetical plugin.  
  > **username_0**: Also, don't forget to register the adjuster: https://craftcms.stackexchange.com/questions/20327/craft-commerce-for-a-discount-can-we-include-all-products-in-the-product-coun/20404?noredirect=1#comment32858_20404  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_2 on 2017-09-10. Score: 3 | Accepted answer
  
  Have you looked into building an adjuster for this purpose? You can find the documentation [here](https://craftcommerce.com/docs/adjusters)
  
  > **Comments:**
  > **username_0**: Hey username_2, thanks for the reply. I've built custom adjusters in the past, so it definitely wouldn't be an issue to get one incorporated. I'm just curious if that is the best way to go or something like using an `onPopulateLineItem` event. Maybe 6 of one, half dozen of another?  
  > **username_3**: Definitely recommend your own discount adjuster if you have advanced logic for reducing the price of line items. Make sure the adjuster class you return runs after the built in discount system to ensure it runs before tax and shipping adjusters.  
  > **username_0**: Cool thanks username_3 (and username_2) -- could you elaborate on why you would recommend the adjuster route vs `onPopuplateLineItem`?  
  > **username_3**: @username_0 `onPopulateLineItem` could also work fine, but you wouldn't be storing the discount calculation or description in an adjustment in the cart. You also could have other line items containing the same product, and `onPopulateLineItem` only cares about the qty of a single line item - an adjuster could look at the whole cart and see 2 line items both with the same product in them and add a single adjustment.  
  
  ---
  
  