Skip to content

Commit 9c368a1

Browse files
committed
ACP2E-3693: Wrong catalog price rule discount applied to the child product
1 parent 27217d0 commit 9c368a1

File tree

3 files changed

+85
-41
lines changed

3 files changed

+85
-41
lines changed

app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProduct.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2017 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -129,6 +129,18 @@ public function execute(Rule $rule, $batchCount, $useAdditionalTable = false)
129129
continue;
130130
}
131131

132+
if (isset($validationByWebsite['has_antecedent_rule'])) {
133+
$antecedentRuleProductList = array_keys(
134+
$connection->fetchAssoc(
135+
$connection->select()->from($indexTable)
136+
->where('product_id = ?', $productId)
137+
->where('rule_id NOT IN (?)', $rule->getId())
138+
->where('sort_order = ?', $sortOrder)
139+
)
140+
);
141+
$connection->delete($indexTable, ['rule_product_id IN (?)' => $antecedentRuleProductList]);
142+
}
143+
132144
foreach ($customerGroupIds as $customerGroupId) {
133145
if (!array_key_exists($customerGroupId, $excludedWebsites)
134146
|| !in_array((int)$websiteId, array_values($excludedWebsites[$customerGroupId]), true)
Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
11
<?php
22
/**
3-
*
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
65
*/
6+
declare(strict_types=1);
7+
78
namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule;
89

9-
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
1010
use Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider;
11+
use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable as ConfigurableProductsResourceModel;
1112

1213
/**
1314
* Add configurable sub products to catalog rule indexer on full reindex
1415
*/
1516
class ConfigurableProductHandler
1617
{
1718
/**
18-
* @var \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable
19+
* @var ConfigurableProductsResourceModel
1920
*/
20-
private $configurable;
21+
private ConfigurableProductsResourceModel $configurable;
2122

2223
/**
23-
* @var \Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\ConfigurableProductsProvider
24+
* @var ConfigurableProductsProvider
2425
*/
25-
private $configurableProductsProvider;
26+
private ConfigurableProductsProvider $configurableProductsProvider;
2627

2728
/**
2829
* @var array
2930
*/
30-
private $childrenProducts = [];
31+
private array $childrenProducts = [];
3132

3233
/**
33-
* @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $configurable
34+
* @param ConfigurableProductsResourceModel $configurable
3435
* @param ConfigurableProductsProvider $configurableProductsProvider
3536
*/
3637
public function __construct(
37-
\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $configurable,
38-
ConfigurableProductsProvider $configurableProductsProvider
38+
ConfigurableProductsResourceModel $configurable,
39+
ConfigurableProductsProvider $configurableProductsProvider
3940
) {
4041
$this->configurable = $configurable;
4142
$this->configurableProductsProvider = $configurableProductsProvider;
@@ -49,40 +50,71 @@ public function __construct(
4950
* @return array
5051
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
5152
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
53+
* @SuppressWarnings(PHPMD.NPathComplexity)
54+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
5255
*/
5356
public function aroundGetMatchingProductIds(
5457
\Magento\CatalogRule\Model\Rule $rule,
5558
\Closure $proceed
56-
) {
59+
): array {
5760
$productsFilter = $rule->getProductsFilter() ? (array) $rule->getProductsFilter() : [];
5861
if ($productsFilter) {
59-
$parentProductIds = $this->configurable->getParentIdsByChild($productsFilter);
60-
$rule->setProductsFilter(array_unique(array_merge($productsFilter, $parentProductIds)));
62+
$rule->setProductsFilter(
63+
array_unique(
64+
array_merge(
65+
$productsFilter,
66+
$this->configurable->getParentIdsByChild($productsFilter)
67+
)
68+
)
69+
);
6170
}
6271

6372
$productIds = $proceed();
73+
foreach ($productIds as $productId => $productData) {
74+
if ($this->hasAntecedentRule((int) $productId)) {
75+
$productIds[$productId]['has_antecedent_rule'] = true;
76+
}
77+
}
6478

65-
$configurableProductIds = $this->configurableProductsProvider->getIds(array_keys($productIds));
66-
foreach ($configurableProductIds as $productId) {
67-
if (!isset($this->childrenProducts[$productId])) {
68-
$this->childrenProducts[$productId] = $this->configurable->getChildrenIds($productId)[0];
79+
foreach ($this->configurableProductsProvider->getIds(array_keys($productIds)) as $configurableProductId) {
80+
if (!isset($this->childrenProducts[$configurableProductId])) {
81+
$this->childrenProducts[$configurableProductId] =
82+
$this->configurable->getChildrenIds($configurableProductId)[0];
6983
}
70-
$subProductIds = $this->childrenProducts[$productId];
71-
$parentValidationResult = isset($productIds[$productId])
72-
? array_filter($productIds[$productId])
84+
85+
$parentValidationResult = isset($productIds[$configurableProductId])
86+
? array_filter($productIds[$configurableProductId])
7387
: [];
74-
$processAllChildren = !$productsFilter || in_array($productId, $productsFilter);
75-
foreach ($subProductIds as $subProductId) {
76-
if ($processAllChildren || in_array($subProductId, $productsFilter)) {
77-
$childValidationResult = isset($productIds[$subProductId])
78-
? array_filter($productIds[$subProductId])
88+
$processAllChildren = !$productsFilter || in_array($configurableProductId, $productsFilter);
89+
foreach ($this->childrenProducts[$configurableProductId] as $childrenProductId) {
90+
if ($processAllChildren || in_array($childrenProductId, $productsFilter)) {
91+
$childValidationResult = isset($productIds[$childrenProductId])
92+
? array_filter($productIds[$childrenProductId])
7993
: [];
80-
$productIds[$subProductId] = $parentValidationResult + $childValidationResult;
94+
$productIds[$childrenProductId] = $parentValidationResult + $childValidationResult;
8195
}
82-
8396
}
84-
unset($productIds[$productId]);
97+
unset($productIds[$configurableProductId]);
8598
}
99+
86100
return $productIds;
87101
}
102+
103+
/**
104+
* Check if simple product has previously applied rule.
105+
*
106+
* @param int $productId
107+
* @return bool
108+
* @SuppressWarnings(PHPMD.UnusedLocalVariable)
109+
*/
110+
private function hasAntecedentRule(int $productId): bool
111+
{
112+
foreach ($this->childrenProducts as $parent => $children) {
113+
if (in_array($productId, $children)) {
114+
return true;
115+
}
116+
}
117+
118+
return false;
119+
}
88120
}

dev/tests/integration/testsuite/Magento/CatalogRuleConfigurable/Model/Product/Type/Configurable/PriceTest.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2020 Adobe
4+
* All Rights Reserved.
55
*/
66
declare(strict_types=1);
77

@@ -105,27 +105,27 @@ public function testGetFinalPriceWithCustomOptionAndCatalogRulesForChildren(): v
105105
$indexPrices = [
106106
'simple_10' => [
107107
'price' => 10,
108-
'final_price' => 4.5,
109-
'min_price' => 4.5,
108+
'final_price' => 9,
109+
'min_price' => 9,
110110
'max_price' => 9,
111111
'tier_price' => null
112112
],
113113
'simple_20' => [
114114
'price' => 20,
115-
'final_price' => 8,
116-
'min_price' => 8,
115+
'final_price' => 15,
116+
'min_price' => 15,
117117
'max_price' => 15,
118118
'tier_price' => 15
119119
],
120120
'configurable' => [
121121
'price' => 0,
122122
'final_price' => 0,
123-
'min_price' => 4.5,
124-
'max_price' => 23,
123+
'min_price' => 9,
124+
'max_price' => 30,
125125
'tier_price' => 15
126126
],
127127
];
128-
$this->assertConfigurableProductPrice(19.5, 23, $indexPrices);
128+
$this->assertConfigurableProductPrice(24, 30, $indexPrices);
129129
}
130130

131131
/**

0 commit comments

Comments
 (0)