Magento2: 2.1.4 Cannot exclude Category from Promotional Cart Price Rule Conditions

Created on 1 Mar 2017  路  15Comments  路  Source: magento/magento2

Promotional Cart Price Rule Conditions does not work as expected, Cannot exclude category from a promotion rule.

I am trying to exclude a category from a Coupon Code e.g. "10off" but Magento 2.1.4 is not excluding the product from discount calculation of the excluded category or categories .

Preconditions

  1. Magento version 2.1.4
  2. Ngnix, PHP5.6
  3. Existing Configurable Products e.g. "SKU WS05" Sample Data
  4. Existing Categories e.g. Women > Tops, Women > Bottoms (Sample Data)
  5. Children of Configurable products are not visible individually

Steps to reproduce

  1. Create a coupon code under Marketing > Cart Price Rules
  2. Coupon: Specific Coupon
  3. Coupon Code: 10off
  4. Action
    Apply: Percent of product price discount
    Discount Amount: 10

Apply the rule only to cart items matching the following conditions (leave blank for all items).
If ALL of these conditions are TRUE :
Category is not one of 21, 22

see attached "m2-discount-code-issue-2.jpg"
m2-discount-code-issue-2

  1. Save the rule
  2. Go to front end and add a product from the excluded category and apply coupon code 10off see attached "m2-discount-code-issue-1.jpg"
    m2-discount-code-issue-1

Expected result

  1. Products from excluded categories shouldn't get discount and an error message should be displayed
    e.g. "The coupon code "10off" is not valid."

Actual result

  1. Magento 2.1.4 is giving discount on products from excluded categories.
Fixed in 2.2.x Fixed in 2.3.x Clear Description Confirmed Format is valid Reproduced on 2.1.x

Most helpful comment

I think this might be because the rule gets applied to the (uncategorised) simple product of the configurable product.

When applying the discount, the collect function (\Magento\SalesRule\Model\Quote\Discount::collect) skips cart items with a parent:

// to determine the child item discount, we calculate the parent
if ($item->getParentItem()) {
    continue;
}

However, later in the process the applyRules function \Magento\SalesRule\Model\RulesApplier::applyRules fetches the quote items from the quote again, so the simple subproducts are no longer filtered.
Because they are not in a category, they do not get excluded, so the discount gets applied.
So skipping the validation of those products with parent products seems to solve the problem in our situation (we want to exclude products in certain categories from receiving a cart price rule discount).
Because I do not fully understand the inner workings of the SalesRule module I do not know if this might have any side effects.

I changed the following line (2.1.3):

\Magento\SalesRule\Model\RulesApplier::applyRules

if ($rule->getActions()->validate($childItem)) {
    $isContinue = false;
}

To:

/** Child item discount we calculate for parent */
if (!$childItem->getParentItem() && $rule->getActions()->validate($childItem)) {
    $isContinue = false;
}

Full code:
CartRuleFix.zip

All 15 comments

https://github.com/magento/magento2/issues/7508 My related issue which has still not been fixed

@magento-team, any update. This an eCommerce 101 coupon code.

I think this might be because the rule gets applied to the (uncategorised) simple product of the configurable product.

When applying the discount, the collect function (\Magento\SalesRule\Model\Quote\Discount::collect) skips cart items with a parent:

// to determine the child item discount, we calculate the parent
if ($item->getParentItem()) {
    continue;
}

However, later in the process the applyRules function \Magento\SalesRule\Model\RulesApplier::applyRules fetches the quote items from the quote again, so the simple subproducts are no longer filtered.
Because they are not in a category, they do not get excluded, so the discount gets applied.
So skipping the validation of those products with parent products seems to solve the problem in our situation (we want to exclude products in certain categories from receiving a cart price rule discount).
Because I do not fully understand the inner workings of the SalesRule module I do not know if this might have any side effects.

I changed the following line (2.1.3):

\Magento\SalesRule\Model\RulesApplier::applyRules

if ($rule->getActions()->validate($childItem)) {
    $isContinue = false;
}

To:

/** Child item discount we calculate for parent */
if (!$childItem->getParentItem() && $rule->getActions()->validate($childItem)) {
    $isContinue = false;
}

Full code:
CartRuleFix.zip

Is there any fix available for this in 1.9.1.1?

I found this issue in magento2 CE 2.1.7 too. (also in 2.1.5)

For my case, I found that when magento validate the categories condition, it will check from table 'catalog_category_product_index'. This issue happens because of wrong indexing in index id: 'catalog_category_product'. This index table excludes products which have set visibility to 'not visible individually'. You can see the query in Magento\Catalog\Model\Indexer\Category\Product\AbstractAction.php in function createAnchorSelect() and getNonAnchorCategoriesSelect()

                 ->where(
                $this->connection->getIfNullSql('cpvs.value', 'cpvd.value') . ' IN (?)',
                [
                    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_CATALOG,
                    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_IN_SEARCH,
                    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
                ]
            )

try to rewrite these functions and reindex again. you will see product ids with visibility 'not visible individually' in table 'catalog_category_product_index'.

another function you have to fix is Magento/Catalog/Model/ResourceModel/Product.php in function 'getAvailableInCategories'. remove the category filter will fix it.

                    ->where(
                    'visibility != ?',
                    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_NOT_VISIBLE
                ) 

then try to apply rules to cart. it should work correctly.

@asadyar, thank you for your report.
The issue is already fixed in develop branch, 2.2.0

@magento-engcom-team can you post the link to the fix? We are having this issue.

@magento-engcom-team link????

Hi @smdevdk, I had to develop my own fix to that, you can download and install in your store (https://github.com/Imagination-Media/configurable-rule-fix-m2.1).

@igor-imaginemage thank you, will try it out!

Issue still exists in Magento CE 2.2.4

Issue still exists in Magento 2.2.5

@magento-engcom-team The Issue still seems to exist. Can we have a link to the commits that fix this please?

In 2.2.5 I fixed with

<type name="Magento\SalesRule\Model\Quote\ChildrenValidationLocator">
    <arguments>
        <argument name="productTypeChildrenValidationMap" xsi:type="array">
            <item name="configurable" xsi:type="boolean">false</item>
        </argument>
    </arguments>
</type>

see Magento\SalesRule\Model\RulesApplier::applyRules

if (!$this->childrenValidationLocator->isChildrenValidationRequired($item)) {
    continue;
}

im experiencing something similar with bundles, since the simples that comprise of the bundle qualify for the discount, its applying the discount to the bundle as well, even though the bundle does not qualify - has anyone found a fix for this?

Was this page helpful?
0 / 5 - 0 ratings