2

Scenario:
Add a new condition to the cart rules in the section "Apply the rule only to cart items matching the following conditions".
The condition should like this: "If Absolute discount amount is/greater/... {value here}".

Example:"Absolute discount amount is 0".
This means that the item should not be matched if it already has a discount.
Adding the new condition was fairly easy.
I added a plugin on Magento\SalesRule\Model\Rule\Condition\Product. afterLoadAttributeOptions

public function afterLoadAttributeOptions(\Magento\SalesRule\Model\Rule\Condition\Product $subject, \Magento\SalesRule\Model\Rule\Condition\Product $result)
{
    $attributes = $subject->getAttributeOption();
    $attributes['quote_item_absolute_discount'] = __('Absolute discount amount'); 
    asort($attributes);
    $subject->setAttributeOption($attributes);
    return $result;
}

This makes it appear in the backend and behave as it should

Now I tried to validate my new condition:
In the same class I have this around plugin

public function aroundValidate(Product $subject, callable $proceed, \Magento\Framework\Model\AbstractModel $model)
{
    if ($subject->getAttribute() === 'quote_item_absolute_discount') {             //if not checking on quote item, let the original method execute
        if ($model instanceof \Magento\Quote\Model\Quote\Item) {
            //set the value of the absolute discount to the product and let the original method validate it
            $model->getProduct()->setData('quote_item_absolute_discount', $model->getDiscountAmount());
        }
    }
    return $proceed($model);
}

I did this for other conditions and it works nicely.
But in this case, because the rules validation is a separate process from applying the rules, I always get 0 for $model->getDiscountAmount().
Even if there are other rules applied to the cart before my rule, the validation is done before applying all the other rules.
Any idea on how I can make this work?

1 Answer 1

0

I was wrong.
There is no separation between validate and apply rules.
\Magento\SalesRule\Model\RulesApplier::applyRules loops though all the rules (not actually all, they are filtered first based on status and start/end date).
If a rule is valid, then it applies it.
The problem in my case was caused by something else, that I overlooked.
in the same method mentioned above... if a rule is not matched for a configurable product, it is validated against the simple product added to the cart along with the configurable one.
And it my case it matched the simple product.
To solve it I changed the method aroundValidate shown in the question to:

public function aroundValidate(Product $subject, callable $proceed, \Magento\Framework\Model\AbstractModel $model)
{
    if ($subject->getAttribute() === 'quote_item_absolute_discount') {
        //if not checking on quote item, let the original method execute
        if ($model instanceof \Magento\Quote\Model\Quote\Item) {
            //set the value of the discount amount to the product and let the original method validate it
            $product = $model->getProduct();
            if (!$product->hasData('quote_item_absolute_discount')) {
                $model->getProduct()->setData('quote_item_absolute_discount', $model->getDiscountAmount());
            }
            $children = $model->getChildren();
            //make the child items aware of the discount amount.
            if (count($children)) {
                foreach ($children as $child) {
                    $product = $child->getProduct();
                    if (!$product->hasData('quote_item_absolute_discount')) {
                        $child->getProduct()->setData('quote_item_absolute_discount', $model->getDiscountAmount());
                    }
                }
            }
        }
    }
    return $proceed($model);
}

Looks like it's working now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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