2

I want to create a cart price rule condition that checks for a cart item's buyRequest object to act upon it accordingly. A rule should only be applied when that buyRequest contains a certain value.

I followed this howto to create a custom condition for cart price rules. However the condition created shows up in the "conditions" section of the rule.

enter image description here

But I need my condition in the "actions" part of the rule as a cart item condition:

enter image description here

I feel like I am so close but I can't quite figure it out. I also browsed through the core's code for the existing 3 cart item attributes ("Price in cart", "Quantity in cart" and "Row total in cart") but could not figure out what they are doing different to show up down there.

Any hint is welcome, thank you.

1 Answer 1

2

To add new conditions under Cart Item Attribute you need to follow the below steps:

Step 1: Create registration.php under

app/code/M2Expert/SalesRule/registration.php

with below content:

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'M2Expert_SalesRule',
    __DIR__ );

Step 2: Create module.xml under

app/code/M2Expert/SalesRule/etc/module.xml

with content:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="M2Expert_SalesRule" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Backend"/>
            <module name="Magento_Sales"/>
            <module name="Magento_Quote"/>
            <module name="Magento_Checkout"/>
            <module name="Magento_Catalog" />
            <module name="Magento_ConfigurableProduct" />
        </sequence>
    </module>
</config>

Step 3: Create di.xml under:

app/code/M2Expert/SalesRule/etc/di.xml

with content:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\SalesRule\Model\Rule\Condition\Product">
        <plugin name="sales_rule_custom_condition" sortOrder="100" type="M2Expert\SalesRule\Plugin\SalesRule\Conditions\Product"/>
    </type>
</config>

Step 4: Create Product.php under

app/code/M2Expert/SalesRule/Plugin/SalesRule/Conditions/Product.php

with content:

<?php

namespace M2Expert\SalesRule\Plugin\SalesRule\Conditions;

use Magento\Config\Model\Config\Source\Yesno as SourceConfig;

/**
 * Additional attr for validator.
 */
class Product
{
    /**
     * Name For Condition Attribute
     */
    public const CONDITION_ATTRIBUTE_NAME = 'quote_item_is_custom_condition';

    /**
     * @var SourceConfig
     */
    private $sourceConfig;

    public function __construct(
        SourceConfig $sourceConfig
    ) {
        $this->sourceConfig = $sourceConfig;
    }

    /**
     * @param \Magento\Rule\Model\Condition\Product\AbstractProduct $subject
     * @param \Magento\SalesRule\Model\Rule\Condition\Product $result
     *
     * @return \Magento\SalesRule\Model\Rule\Condition\Product
     */
    public function afterLoadAttributeOptions(
        \Magento\Rule\Model\Condition\Product\AbstractProduct $subject,
        \Magento\SalesRule\Model\Rule\Condition\Product $result
    ) {
        $attributes = $subject->getAttributeOption();
        $attributes[self::CONDITION_ATTRIBUTE_NAME] = __('My custom condition');
        $subject->setAttributeOption($attributes);

        return $result;
    }

    /**
     * @param \Magento\Rule\Model\Condition\Product\AbstractProduct $subject
     * @param $result
     *
     * @return array
     */
    public function afterGetValueSelectOptions(\Magento\Rule\Model\Condition\Product\AbstractProduct $subject, $result)
    {
        if ($subject->getAttribute() === self::CONDITION_ATTRIBUTE_NAME) {

            return $this->sourceConfig->toOptionArray();
        }

        return $result;
    }

    /**
     * @param \Magento\Rule\Model\Condition\Product\AbstractProduct $subject
     * @param string $result
     *
     * @return string
     */
    public function afterGetInputType(\Magento\Rule\Model\Condition\Product\AbstractProduct $subject, $result)
    {
        if ($subject->getAttribute() === self::CONDITION_ATTRIBUTE_NAME) {
            return 'boolean';
        }

        return $result;
    }

    /**
     * @param \Magento\Rule\Model\Condition\Product\AbstractProduct $subject
     * @param string $result
     *
     * @return string
     */
    public function afterGetValueElementType(\Magento\Rule\Model\Condition\Product\AbstractProduct $subject, $result)
    {
        if ($subject->getAttribute() === self::CONDITION_ATTRIBUTE_NAME) {
            return 'select';
        }

        return $result;
    }

    /**
     * @param \Magento\Rule\Model\Condition\Product\AbstractProduct $subject
     * @param array $result
     *
     * @return array
     */
    public function afterGetOperatorSelectOptions(
        \Magento\Rule\Model\Condition\Product\AbstractProduct $subject,
        $result
    ) {
        if ($subject->getAttribute() === self::CONDITION_ATTRIBUTE_NAME) {
            foreach ($result as $key => $item) {
                if ($item['value'] === '<=>') {
                    unset($result[$key]);
                }
            }
        }

        return $result;
    }

    /**
     * @param \Magento\Rule\Model\Condition\Product\AbstractProduct $subject
     * @param \Magento\Framework\Model\AbstractModel $object
     */
    public function beforeValidate(
        \Magento\Rule\Model\Condition\Product\AbstractProduct $subject,
        \Magento\Framework\Model\AbstractModel $object
    ) {
        if ($object instanceof \Magento\Quote\Api\Data\CartItemInterface
            && $object->getQuote()
            && $object->getQuote()->getItems()
        ) {
            // your logic goes here
        }
    }
}

Thats it!!!! Run all the necessary commands and check in admin.

3
  • Thank you. That worked so far. But where and how do I validate the conditions? I need to evaluate a cart item and return true or false depending on a custom entry in its' buyRequest.
    – omsta
    Apr 26, 2023 at 13:42
  • Check my updated answer, you can put your logic under beforeValidate method. Apr 26, 2023 at 14:09
  • 1
    Got it now, thx.
    – omsta
    Apr 26, 2023 at 14:25

Your Answer

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

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