<p>I would turn this on it's head slightly (assuming you can express the discount itself, i.e. what it does specifically to the discount item, using normal Commerce discount rules).</p>

<p>If you can, then you can basically make the application of the discount conditional based on what's in the cart.</p>

<p>Here's some sketch code - obviously you might need to change the logic etc</p>

<pre><code>public function onBeforeMatchLineItemHandler($event){

$lineItem = $event-&gt;params['lineItem'];
$discount = $event-&gt;params['discount'];

$cart = craft()-&gt;commerce_cart-&gt;getCart();

$idOfItemToPossiblyDiscount = whatever;
$idOfParentItem = whatever;
$idOfDiscount = whatever;

/First check which discount we're thinking about applying
if($discount-&gt;id == $idOfDiscount){

    $shouldDiscount = false;
    if ($lineItem-&gt;purchasable instanceof Commerce_VariantModel){
        //First check if this is the item that might get discounted
        if($lineItem-&gt;purchasable-&gt;id) == $idOfItemToPossiblyDiscount)){
            //Ok, so we have that item in the cart now loop through $cart to see if the 'parent' item is in the cart
            foreach ($cart-&gt;lineItems as $item){
                if ($item-&gt;purchasable-&gt;$id) == $idOfParentItem){
                    //do nothing, but finish here - Commerce will carry on and apply the discount as long as
                    //we dont set event-&gt;performAction = false;
                    $shouldDiscount = true;
                    break;
                }
            }

        }

    }

    if(!$shouldDiscount){
        $event-&gt;performAction = false;
    }

}
</code></pre>

<p>Obviously at the template end of things you can loop through what's in the cart and do similar logic to show messages etc - e.g. if parent item is in, and not the discount item, present the offer, etc....</p>

CC BY-SA 3.0
2016-06-05T01:30:23.457Z
Thank you, Jeremy - I have updated my question with things I have tried. I swear the handler fired once. I saved my project and when I came back the event is no longer firing.
Damon
CC BY-SA 3.0
2016-06-05T01:52:08.737Z
Well, I think I might have (finally) started to get out of my own way. I'll update my post for others as I go. Thank you again for your help!
Damon
CC BY-SA 3.0
2016-05-30T23:44:10.027Z
2016-05-30T23:44:10.027Z
Jeremy Daalder
<p>I am inspecting my cart when the user visits <code>/commerce/cart</code> and if the cart contains a specific product, I want to alert the user that they can redeem a credit for "x" item. If the users chooses to use the credit, I would like to assign the qualifying product a discount.</p>

<pre><code>...
if ($lineItems) {
    foreach ($lineItems as $lineItem) {
        foreach ($lineItem-&gt;purchasable-&gt;product-&gt;foo as $bar) {

            ...
            // qualifying product found - return json to javascript
            ...
        }
...

$discount = new commerce_DiscountModel();
...
??
// apply discount to cart/update ui via javascript to reflect discount
</code></pre>

<p>I'm able get all the way up to creating a new discount. I assume I start by creating a new discount model and populate it with the price of the product I am wanting to discount? I'm not really sure where to start - thank you for any suggestions!</p>

<p><strong>EDIT</strong></p>

<p>First off, thank you, Jeremy for your help. I (think) I am slowly starting to understand. I don't understand how or why the handler is or isn't getting called. </p>

<p>Here is my updated main plugin file:</p>

<p><strong>MyPlugin.php</strong></p>

<pre><code>public function init()
{
    error_log(__FUNCTION__); // this is logged

    craft()-&gt;on('commerce_discounts.onBeforeMatchLineItem',
        [
            craft()-&gt;myPlugin, 
            'onBeforeMatchLineItemHandler'
        ]
    );
    ...
}
</code></pre>

<p>Then my service file looks like this:</p>

<p><strong>MyPluginService.php</strong></p>

<pre><code>class MyPluginService extends BaseApplicationComponent
{
    public function onBeforeMatchLineItemHandler($event)
    {
        // this method never gets executed

        $cart = craft()-&gt;commerce_cart-&gt;getCart();
        $lineItem = $event-&gt;params['lineItem'];
        $discount = $event-&gt;params['discount'];

        error_log('line item: ' . $lineItem);
        error_log('discount: ' . $discount);
    }

    ...
}
</code></pre>

<p>If I change the name of the handler to "myPluginz" or something that doesn't exist, it throws an error, so I know I have the right syntax at least. </p>

<p>The handler was actually called once, but now it never gets executed. The product I have in my cart is promotable, and is not excluded from any sale. So it seems I am matching the criteria needed.</p>

<p>I also tried this straight from the docs.</p>

<pre><code>public function init()
{
    error_log(__FUNCTION__); // this is logged
    craft()-&gt;on('commerce_discounts.onBeforeMatchLineItem', function ($event) {
        error_log(print_r($event, true)); // this is not executed

    });
}
</code></pre>

<p>I don't understand what I've done wrong to cause the event not to fire.</p>

<p><strong>EDIT 2</strong></p>

<p>Well, I think I have finally managed to get out of my own way. I'll update this thread as I progress through.</p>

<plugin-development><plugin-craftcommerce>
Commerce: How can I dynamically create a discount for any given product?
# Commerce: How can I dynamically create a discount for any given product?

(Asked by: username_0 on 2016-05-30)

I am inspecting my cart when the user visits /commerce/cart and if the cart contains a specific product, I want to alert the user that they can redeem a credit for "x" item. If the users chooses to use the credit, I would like to assign the qualifying product a discount.
...
if ($lineItems) {
    foreach ($lineItems as $lineItem) {
        foreach ($lineItem->purchasable->product->foo as $bar) {

            ...
            // qualifying product found - return json to javascript
            ...
        }
...

$discount = new commerce_DiscountModel();
...
??
// apply discount to cart/update ui via javascript to reflect discount

I'm able get all the way up to creating a new discount. I assume I start by creating a new discount model and populate it with the price of the product I am wanting to discount? I'm not really sure where to start - thank you for any suggestions!
EDIT
First off, thank you, Jeremy for your help. I (think) I am slowly starting to understand. I don't understand how or why the handler is or isn't getting called. 
Here is my updated main plugin file:
MyPlugin.php
public function init()
{
    error_log(__FUNCTION__); // this is logged

    craft()->on('commerce_discounts.onBeforeMatchLineItem',
        [
            craft()->myPlugin, 
            'onBeforeMatchLineItemHandler'
        ]
    );
    ...
}

Then my service file looks like this:
MyPluginService.php
class MyPluginService extends BaseApplicationComponent
{
    public function onBeforeMatchLineItemHandler($event)
    {
        // this method never gets executed

        $cart = craft()->commerce_cart->getCart();
        $lineItem = $event->params['lineItem'];
        $discount = $event->params['discount'];

        error_log('line item: ' . $lineItem);
        error_log('discount: ' . $discount);
    }

    ...
}

If I change the name of the handler to "myPluginz" or something that doesn't exist, it throws an error, so I know I have the right syntax at least. 
The handler was actually called once, but now it never gets executed. The product I have in my cart is promotable, and is not excluded from any sale. So it seems I am matching the criteria needed.
I also tried this straight from the docs.
public function init()
{
    error_log(__FUNCTION__); // this is logged
    craft()->on('commerce_discounts.onBeforeMatchLineItem', function ($event) {
        error_log(print_r($event, true)); // this is not executed

    });
}

I don't understand what I've done wrong to cause the event not to fire.
EDIT 2
Well, I think I have finally managed to get out of my own way. I'll update this thread as I progress through.

**Tags:** plugin-development, plugin-craftcommerce

---

## 1 answers

### Answer by username_1 on 2016-05-30. Score: 2

I would turn this on it's head slightly (assuming you can express the discount itself, i.e. what it does specifically to the discount item, using normal Commerce discount rules).
If you can, then you can basically make the application of the discount conditional based on what's in the cart.
Here's some sketch code - obviously you might need to change the logic etc
public function onBeforeMatchLineItemHandler($event){

$lineItem = $event->params['lineItem'];
$discount = $event->params['discount'];

$cart = craft()->commerce_cart->getCart();

$idOfItemToPossiblyDiscount = whatever;
$idOfParentItem = whatever;
$idOfDiscount = whatever;

/First check which discount we're thinking about applying
if($discount->id == $idOfDiscount){

    $shouldDiscount = false;
    if ($lineItem->purchasable instanceof Commerce_VariantModel){
        //First check if this is the item that might get discounted
        if($lineItem->purchasable->id) == $idOfItemToPossiblyDiscount)){
            //Ok, so we have that item in the cart now loop through $cart to see if the 'parent' item is in the cart
            foreach ($cart->lineItems as $item){
                if ($item->purchasable->$id) == $idOfParentItem){
                    //do nothing, but finish here - Commerce will carry on and apply the discount as long as
                    //we dont set event->performAction = false;
                    $shouldDiscount = true;
                    break;
                }
            }

        }

    }

    if(!$shouldDiscount){
        $event->performAction = false;
    }

}

Obviously at the template end of things you can loop through what's in the cart and do similar logic to show messages etc - e.g. if parent item is in, and not the discount item, present the offer, etc....

> **Comments:**
> **username_0**: Thank you, Jeremy - I have updated my question with things I have tried. I swear the handler fired once. I saved my project and when I came back the event is no longer firing.  
> **username_0**: Well, I think I might have (finally) started to get out of my own way. I'll update my post for others as I go. Thank you again for your help!  

---

