phpmagento2

Magento 2 after apply coupon code does not apply other cart rules


I am using Magento 2 with the Amasty_Promo module. And this module allow to add some promo/free gifts in the cart against some cart rules.Test case is like this

If my cart have some free/promo items in the cart and then if i apply the coupon or any wrong coupon code then it remove the previous rules related free items / promo items from the cart. So no free gifts are there.

Can you please help me and let me know why it is happening? Thank you very much


Solution

  • I have found it's reason and it is a very solid reason.

    In Magento 2 by default there are four types of rules

    1. Percent of product price discount
    2. Fixed Amount discount
    3. Fixed Amount discount for whole cart
    4. Buy X get Y free

    So if we see above four rules we will draw a conclusion

    The above conclusion make sense if we have only discount based promotion. But if we add new rules or if we add any 3rd party module such as Amasty Promo module. The we also got some options to add a free gifts related rules.

    So now in the above scenario where our site will provide discount and free gifts. And in case when customer cart have both discount against coupon based rule and free gift then Magento will only apply the coupon based rules and ignore all other rules.

    Solution:

    We can achieve our requirement by override the \Magento\SalesRule\Model\Validator

    etc/di.xml will be like this

    <?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    
        <!-- We override it to apply the Amasty_Promo rules even after apply the coupon code -->
        <preference for="\Magento\SalesRule\Model\Validator" type="\YourPackage\YourModule\Rewrite\SalesRule\Model\Validator" />
    </config>
    

    YourPackage\YourModule\Rewrite\SalesRule\Model\Validator.php

    namespace YourPackage\YourModule\Rewrite\SalesRule\Model;
    
    use Magento\Quote\Model\Quote\Address;
    use Magento\Quote\Model\Quote\Item\AbstractItem;
    
    class Validator extends \Magento\SalesRule\Model\Validator
    {
        /**
         * Quote item discount calculation process
         *
         * @param AbstractItem $item
         * @return $this
         */
        public function process(AbstractItem $item)
        {
            $item->setDiscountAmount(0);
            $item->setBaseDiscountAmount(0);
            $item->setDiscountPercent(0);
    
            $itemPrice = $this->getItemPrice($item);
            if ($itemPrice < 0) {
                return $this;
            }
    
            $appliedRuleIds = array();
    
            if($this->getCouponCode()) {
                $appliedRuleIds = $this->rulesApplier->applyRules(
                    $item,
                    $this->_getRules($item->getAddress()),
                    $this->_skipActionsValidation,
                    $this->getCouponCode()
                );
            }
            $promoItemRuleIds = $this->rulesApplier->applyRules(
                $item,
                $this->_getPromoItemRules($item->getAddress()),
                $this->_skipActionsValidation,
                $this->getCouponCode()
            );
    
            $appliedRuleIds = array_merge($appliedRuleIds,$promoItemRuleIds );
    
            $this->rulesApplier->setAppliedRuleIds($item, $appliedRuleIds);
    
            return $this;
        }
    
        /**
         * Get rules of promo items
         *
         * @param Address|null $address
         * @return \Magento\SalesRule\Model\ResourceModel\Rule\Collection
         */
        protected function _getPromoItemRules(Address $address = null)
        {
            $addressId = $this->getAddressId($address);
            $key = $this->getWebsiteId() . '_'
                . $this->getCustomerGroupId() . '_'
                . '_'
                . $addressId;
            if (!isset($this->_rules[$key])){
                $this->_rules[$key] = $this->_collectionFactory->create()
                    ->setValidationFilter(
                        $this->getWebsiteId(),
                        $this->getCustomerGroupId(),
                        '',
                        null,
                        $address
                    )
                    ->addFieldToFilter('is_active', 1)
                    ->addFieldToFilter('simple_action', array('like'=>'%ampromo%'))//Condition for promo rules only
                    ->load();
            }
            return $this->_rules[$key];
        }
    }