<p>Success!</p>

<p>1) I have an Event that does a EVENT_BEFORE_SAVE_ELEMENT check.</p>

<pre><code>Event::on(Elements::class, Elements::EVENT_BEFORE_SAVE_ELEMENT, function(Event $event){

    /**
     *  Runs so an admin doesn't have to set SKU or Slug when creating a NEW SONG
     *  This Event will also set the Price based on the Price Group Category Selected
     */

    // Only perform action if we are working with a Digital Product and Song Type
    if ( ($event-&gt;element instanceof \craft\digitalproducts\elements\Product) &amp;&amp; ($event-&gt;element-&gt;typeId == 1) ) {

        // Only adjust the SKU and Slug if this is a NEW Digital Product
        if ($event-&gt;isNew) {

            // Get the last row from the Content Table
            $lastId = (new \craft\db\Query())
                -&gt;select([
                    'elements.id'
                ])
                -&gt;from('elements')
                -&gt;orderBy('id DESC')
                -&gt;limit(1)
                -&gt;one();

            // Increment the Last ID number by One. This will work fine unless the last item was deleted.
            // But the point of this is to assign a new, unused number to the Slug and SKU anyway
            $songId = $lastId['id'] + 1;

            // Assign the SKU and Slug
            $event-&gt;element-&gt;sku = 'song-' . $songId;
            $event-&gt;element-&gt;slug = $songId;
        }

        // Get the price from the Price Category
        $categories = $event-&gt;element-&gt;getfieldValue('priceCategory')-&gt;one();
        $productPrice = $categories['productPrice'];

        $event-&gt;element-&gt;price = $productPrice;
    }
});
</code></pre>

<p>I also have a method that checks the Categories. If the price changes there, then it goes back and updates the prices on all the products, too.</p>

<p>2) Then, to connect the Verbb Gift Voucher plugin and to adjust the Line Items by a percent discount, I run this EVENT_REGISTER_ORDER_ADJUSTERS</p>

<pre><code>Event::on(OrderAdjustments::class, OrderAdjustments::EVENT_REGISTER_ORDER_ADJUSTERS, function(RegisterComponentTypesEvent $event) {
    $event-&gt;types[] = CartAdjustmentsAdjuster::class;
});
</code></pre>

<p>which is this:
    class CartAdjustmentsAdjuster implements AdjusterInterface
    {</p>

<pre><code>    // Properties
    // =========================================================================

    private $_orderLineItems;

    // Public Methods
    // =========================================================================

    public function adjust(Order $order): array
    {
        $adjustments = [];

        $this-&gt;_orderLineItems = $order-&gt;getLineItems();

        // Get the Voucher code by session
        $giftVoucherCodes = Craft::$app-&gt;getSession()-&gt;get('giftVoucher.giftVoucherCodes');

        if (!$giftVoucherCodes || count($giftVoucherCodes) == 0) {
            return [];
        }

        foreach ($giftVoucherCodes as $giftVoucherCode) {
            $voucherCode = Code::find()
                -&gt;where(['=', 'codeKey', $giftVoucherCode])
                -&gt;one();

            if ($voucherCode) {

                $priceAdjust = (new \craft\db\Query())
                    -&gt;select([
                        'content.field_prePayDiscount'
                    ])
                    -&gt;from('content')
                    -&gt;innerJoin('giftvoucher_codes', '[[giftvoucher_codes.voucherId]] = [[content.elementId]]')
                    -&gt;where(['=', 'giftvoucher_codes.codeKey', $voucherCode])
                    -&gt;all();

                $discount = $priceAdjust[0]['field_prePayDiscount'];
                if($discount &gt; 0) {

                    foreach ($this-&gt;_orderLineItems as $item)
                    {
                        $origAmt = $item-&gt;price;
                        $saleAmt = ($discount / 100);
                        $discountAmt = $saleAmt * $origAmt;
                        $discountPrice = $origAmt - $discountAmt;

                        $item-&gt;saleAmount = $saleAmt;
                        $item-&gt;salePrice = $discountPrice;
                    }
                }
            }
        }

        return $adjustments;
    }
}
</code></pre>

<p>One important note is that this custom adjuster needs to be installed first before the Verbb Gift Voucher plugin so that the Gift Voucher amount will be applied after the Line Item adjustments are made.</p>

<p>The <a href="https://docs.craftcms.com/commerce/v2/adjusters.html#register-a-new-adjuster" rel="nofollow noreferrer">docs</a> state:</p>

<blockquote>
  <p>You could have a project level event listener, that could reorder these adjusters, and not append any new ones.</p>
</blockquote>

<p>But installing in this order works, too.</p>

CC BY-SA 4.0
2018-12-01T04:29:41.883Z
I assume I should probably move those DB queries into a Service, but right now I'm just excited that it all works!
Marc Miller
CC BY-SA 4.0
2018-12-01T04:28:15.957Z
2018-12-01T05:11:16.143Z
2018-12-01T05:11:16.143Z
Marc Miller
<p>I'm writing a custom plugin for a customer that does 2 things.</p>

<ol>
<li>Uses prices from Pricing Categories. There are 10,000 digital products, so adjusting prices for large quantities is cumbersome on a per-product basis.</li>
<li>Uses a Stock Photo model system of PrePay. Purchase a set amount of credits like $100, and get 10% off the products.</li>
</ol>

<p><strike>I have successfully completed the first step by using the <code>EVENT_POPULATE_LINE_ITEM</code> listener. The following works perfectly.</strike></p>

<p>Upon consultation with the wonderful Michael Rog, I am taking a different apporoach to this project.</p>

<ol>
<li><p>Create a function on the backend that upon an product entry save, assign the price from the category. This will assign the price in the CP, rather than doing any line item editing and cart manipulation on the front end.</p></li>
<li><p>I will be creating my own adjuster that will fire after a Gift Voucher has been added to the cart that will then apply the sale percentage to the line item in addition to the whole voucher process.</p></li>
</ol>

<p>I'll post my update when successful.</p>

<plugin-development><plugin-craftcommerce2><adjusters>
Check for whole cart adjustment and apply line item discount
# Check for whole cart adjustment and apply line item discount

(Asked by: username_0 on 2018-11-27)

I'm writing a custom plugin for a customer that does 2 things.

1. Uses prices from Pricing Categories. There are 10,000 digital products, so adjusting prices for large quantities is cumbersome on a per-product basis.
2. Uses a Stock Photo model system of PrePay. Purchase a set amount of credits like $100, and get 10% off the products.

I have successfully completed the first step by using the `EVENT_POPULATE_LINE_ITEM` listener. The following works perfectly.

Upon consultation with the wonderful Michael Rog, I am taking a different apporoach to this project.

1. Create a function on the backend that upon an product entry save, assign the price from the category. This will assign the price in the CP, rather than doing any line item editing and cart manipulation on the front end.
2. I will be creating my own adjuster that will fire after a Gift Voucher has been added to the cart that will then apply the sale percentage to the line item in addition to the whole voucher process.

I'll post my update when successful.

**Tags:** plugin-development, plugin-craftcommerce2, adjusters

---

## 1 answers

### Answer by username_0 on 2018-12-01. Score: 2 | Accepted answer

Success!
1) I have an Event that does a EVENT_BEFORE_SAVE_ELEMENT check.
Event::on(Elements::class, Elements::EVENT_BEFORE_SAVE_ELEMENT, function(Event $event){

    /**
     *  Runs so an admin doesn't have to set SKU or Slug when creating a NEW SONG
     *  This Event will also set the Price based on the Price Group Category Selected
     */

    // Only perform action if we are working with a Digital Product and Song Type
    if ( ($event->element instanceof \craft\digitalproducts\elements\Product) && ($event->element->typeId == 1) ) {

        // Only adjust the SKU and Slug if this is a NEW Digital Product
        if ($event->isNew) {

            // Get the last row from the Content Table
            $lastId = (new \craft\db\Query())
                ->select([
                    'elements.id'
                ])
                ->from('elements')
                ->orderBy('id DESC')
                ->limit(1)
                ->one();

            // Increment the Last ID number by One. This will work fine unless the last item was deleted.
            // But the point of this is to assign a new, unused number to the Slug and SKU anyway
            $songId = $lastId['id'] + 1;

            // Assign the SKU and Slug
            $event->element->sku = 'song-' . $songId;
            $event->element->slug = $songId;
        }

        // Get the price from the Price Category
        $categories = $event->element->getfieldValue('priceCategory')->one();
        $productPrice = $categories['productPrice'];

        $event->element->price = $productPrice;
    }
});

I also have a method that checks the Categories. If the price changes there, then it goes back and updates the prices on all the products, too.
2) Then, to connect the Verbb Gift Voucher plugin and to adjust the Line Items by a percent discount, I run this EVENT_REGISTER_ORDER_ADJUSTERS
Event::on(OrderAdjustments::class, OrderAdjustments::EVENT_REGISTER_ORDER_ADJUSTERS, function(RegisterComponentTypesEvent $event) {
    $event->types[] = CartAdjustmentsAdjuster::class;
});

which is this:
    class CartAdjustmentsAdjuster implements AdjusterInterface
    {
    // Properties
    // =========================================================================

    private $_orderLineItems;

    // Public Methods
    // =========================================================================

    public function adjust(Order $order): array
    {
        $adjustments = [];

        $this->_orderLineItems = $order->getLineItems();

        // Get the Voucher code by session
        $giftVoucherCodes = Craft::$app->getSession()->get('giftVoucher.giftVoucherCodes');

        if (!$giftVoucherCodes || count($giftVoucherCodes) == 0) {
            return [];
        }

        foreach ($giftVoucherCodes as $giftVoucherCode) {
            $voucherCode = Code::find()
                ->where(['=', 'codeKey', $giftVoucherCode])
                ->one();

            if ($voucherCode) {

                $priceAdjust = (new \craft\db\Query())
                    ->select([
                        'content.field_prePayDiscount'
                    ])
                    ->from('content')
                    ->innerJoin('giftvoucher_codes', '[[giftvoucher_codes.voucherId]] = [[content.elementId]]')
                    ->where(['=', 'giftvoucher_codes.codeKey', $voucherCode])
                    ->all();

                $discount = $priceAdjust[0]['field_prePayDiscount'];
                if($discount > 0) {

                    foreach ($this->_orderLineItems as $item)
                    {
                        $origAmt = $item->price;
                        $saleAmt = ($discount / 100);
                        $discountAmt = $saleAmt * $origAmt;
                        $discountPrice = $origAmt - $discountAmt;

                        $item->saleAmount = $saleAmt;
                        $item->salePrice = $discountPrice;
                    }
                }
            }
        }

        return $adjustments;
    }
}

One important note is that this custom adjuster needs to be installed first before the Verbb Gift Voucher plugin so that the Gift Voucher amount will be applied after the Line Item adjustments are made.
The docs state:

You could have a project level event listener, that could reorder these adjusters, and not append any new ones.

But installing in this order works, too.

> **Comments:**
> **username_0**: I assume I should probably move those DB queries into a Service, but right now I'm just excited that it all works!  

---

