Magento2 – Exclude Product from Cart Rules with Catalog Rule Discount

checkoutmagento2shopping-cart-price-rules

I have overridden the below function for business logic(Want to exclude a product from cart rule which has catalog rule applied on the product) and it's working fine on the cart page

vendor/magento/module-sales-rule/Model/RulesApplier.php

Function Name setDiscountData

$discountAmount=$catalogrulecheck->getCatalogPriceRuleFromProduct($item->getProduct()->getId(),$customerGroupId);
      if($discountAmount ==0) {
      $item->setDiscountAmount($discountData->getAmount());
      $item->setBaseDiscountAmount($discountData->getBaseAmount());
      $item->setOriginalDiscountAmount($discountData->getOriginalAmount());
      $item->setBaseOriginalDiscountAmount($discountData->getBaseOriginalAmount());
      return $this;
  }

but when I come to the checkout page then it's loading functionality from the core file, not from the override module.

I tried to override applyRules function from the same file

public function applyRules($item, $rules, $skipValidation, $couponCode)
{ 
    $address = $item->getAddress();
    $appliedRuleIds = [];
    $this->discountAggregator = [];
    /* @var $rule Rule */
    foreach ($rules as $rule) {
        if (!$this->validatorUtility->canProcessRule($rule, $address)) {
            continue;
        }
        if (!$skipValidation && !$rule->getActions()->validate($item)) {
            if (!$this->childrenValidationLocator->isChildrenValidationRequired($item)) {
                continue;
            }
            $childItems = $item->getChildren();
            $isContinue = true;
            if (!empty($childItems)) {
                foreach ($childItems as $childItem) {
                    if ($rule->getActions()->validate($childItem)) {
                        $isContinue = false;
                    }
                }
            }
            if ($isContinue) {
                continue;
            }
        }

        $this->applyRule($item, $rule, $address, $couponCode);
        $appliedRuleIds[$rule->getRuleId()] = $rule->getRuleId();

        if ($rule->getStopRulesProcessing()) {
            break;
        }
    }

    return $appliedRuleIds;
}

it's also working in the cart but when I come to the checkout page that time it's loading from the core file

Below are the di.xml file

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/framework/ObjectManager/etc/config.xsd">
    <preference for="Magento\SalesRule\Model\RulesApplier" type="[Vendor]\[Module]\Model\RulesApplier"/>
</config>

Please let me know what's wrong with this.

Best Answer

Here we have 2 solutions for this task

1 Solution: Move Di.xml from frontend folder to global location like below

app/code/[Vendor]/[Module]/etc/di.xml

and it will work in both areas like the cart page and checkout(area is different) page.

2 Solution: Best Way

Create plugin for public method on below location

app/code/[Vendor]/[Module]/etc/di.xml

add below code in above created file

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <type name="Magento\SalesRule\Model\RulesApplier">
        <plugin name="remove_cart_rule" type="[Vendor]\[Module]\Plugin\SalesRule\Model\RulesApplier"/>
    </type>
</config>

After that create a new file RulesApplier.php on the below location

app/code/[Vendor]/[Module]/Plugin/SalesRule/Model

add below code in above created file

<?php

namespace [Vendor]/[Module]\Plugin\SalesRule\Model;

use Magento\Framework\Stdlib\DateTime\TimezoneInterface;

class RulesApplier
{
    public function __construct(
        \Magento\CatalogRule\Model\ResourceModel\Rule $rule,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        TimezoneInterface $dateTime,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Framework\App\Http\Context $httpContext
    ) {
        $this->scopeConfig = $scopeConfig;
        $this->dateTime = $dateTime;
        $this->rule = $rule;
        $this->httpContext = $httpContext;
        $this->storeManager = $storeManager;
    }

    const CART_MODULE_STATUS='cartrule/general/enable';

    public function aroundApplyRules(
        \Magento\SalesRule\Model\RulesApplier $subject,
        \Closure $proceed,
        $item,
        $rules,
        $skipValidation,
        $couponCode
    ) {
        if ($this->getModuleStatus()) {
            $isAppliedCatalogRules = $this->getCatalogPriceRuleFromProduct($item->getProduct()->getId());
            if ($isAppliedCatalogRules) {
                return [];
            }
        }
        $result = $proceed($item, $rules, $skipValidation, $couponCode);
        return $result;
    }

    public function getCatalogPriceRuleFromProduct($productId)
    {
        $dateTs = $this->dateTime->scopeDate($this->storeManager->getStore()->getId());
        $websiteId = $this->storeManager->getWebsite()->getId();
        $customerGroupId = $this->httpContext->getValue(\Magento\Customer\Model\Context::CONTEXT_GROUP);

        $rules = $this->rule->getRulesFromProduct($dateTs, $websiteId, $customerGroupId, $productId);
        return count($rules);
    }

    public function getModuleStatus()
    {
        return $this->scopeConfig->getValue(
            self::CART_MODULE_STATUS,
            \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITES,
            $this->storeManager->getWebsite()->getId()
        );
    }
}
Related Topic