<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>

CC BY-SA 3.0
2017-09-11T13:07:52.863Z
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?
Peter Tell
CC BY-SA 3.0
2017-09-12T02:26:36.963Z
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.
Luke Holder
CC BY-SA 3.0
2017-09-12T14:56:13.363Z
Cool thanks Luke (and Andris) -- could you elaborate on why you would recommend the adjuster route vs `onPopuplateLineItem`?
Peter Tell
CC BY-SA 3.0
2017-09-13T06:35:08.573Z
@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.
Luke Holder
CC BY-SA 3.0
2017-09-10T08:37:31.703Z
2017-09-10T08:37:31.703Z
Andris Sevcenko
<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>

CC BY-SA 3.0
2018-03-03T15:28:08.883Z
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...
outline4
CC BY-SA 3.0
2018-03-23T21:08:10.797Z
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.
Peter Tell
CC BY-SA 3.0
2018-03-23T21:13:49.867Z
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
Peter Tell
<plugin-craftcommerce>
Craft Commerce: How do I handle quantity based discounts on a product level?
# 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 Luke and Andris 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
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 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...  
> **username_0**: 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.  
> **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 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?  
> **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 Luke (and Andris) -- could you elaborate on why you would recommend the adjuster route vs `onPopuplateLineItem`?  
> **username_3**: @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.  

---

