Skip to content

Commit 1b2617c

Browse files
committed
Merge remote-tracking branch 'magento-l3/ACP2E-330' into L3_PR_21-12-10
2 parents 5e8260f + 18e453d commit 1b2617c

File tree

3 files changed

+223
-42
lines changed

3 files changed

+223
-42
lines changed

app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandler.php

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,26 @@ public function __construct(
4242
}
4343

4444
/**
45+
* Match configurable child products if configurable product match the condition
46+
*
4547
* @param \Magento\CatalogRule\Model\Rule $rule
46-
* @param array $productIds
48+
* @param \Closure $proceed
4749
* @return array
4850
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
51+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
4952
*/
50-
public function afterGetMatchingProductIds(\Magento\CatalogRule\Model\Rule $rule, array $productIds)
51-
{
53+
public function aroundGetMatchingProductIds(
54+
\Magento\CatalogRule\Model\Rule $rule,
55+
\Closure $proceed
56+
) {
57+
$productsFilter = $rule->getProductsFilter() ? (array) $rule->getProductsFilter() : [];
58+
if ($productsFilter) {
59+
$parentProductIds = $this->configurable->getParentIdsByChild($productsFilter);
60+
$rule->setProductsFilter(array_unique(array_merge($productsFilter, $parentProductIds)));
61+
}
62+
63+
$productIds = $proceed();
64+
5265
$configurableProductIds = $this->configurableProductsProvider->getIds(array_keys($productIds));
5366
foreach ($configurableProductIds as $productId) {
5467
if (!isset($this->childrenProducts[$productId])) {
@@ -58,11 +71,15 @@ public function afterGetMatchingProductIds(\Magento\CatalogRule\Model\Rule $rule
5871
$parentValidationResult = isset($productIds[$productId])
5972
? array_filter($productIds[$productId])
6073
: [];
74+
$processAllChildren = !$productsFilter || in_array($productId, $productsFilter);
6175
foreach ($subProductIds as $subProductId) {
62-
$childValidationResult = isset($productIds[$subProductId])
63-
? array_filter($productIds[$subProductId])
64-
: [];
65-
$productIds[$subProductId] = $parentValidationResult + $childValidationResult;
76+
if ($processAllChildren || in_array($subProductId, $productsFilter)) {
77+
$childValidationResult = isset($productIds[$subProductId])
78+
? array_filter($productIds[$subProductId])
79+
: [];
80+
$productIds[$subProductId] = $parentValidationResult + $childValidationResult;
81+
}
82+
6683
}
6784
unset($productIds[$productId]);
6885
}

app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ConfigurableProductHandlerTest.php

Lines changed: 123 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ protected function setUp(): void
4444
{
4545
$this->configurableMock = $this->createPartialMock(
4646
Configurable::class,
47-
['getChildrenIds']
47+
['getChildrenIds', 'getParentIdsByChild']
4848
);
4949
$this->configurableProductsProviderMock = $this->createPartialMock(
5050
ConfigurableProductsProvider::class,
@@ -61,29 +61,38 @@ protected function setUp(): void
6161
/**
6262
* @return void
6363
*/
64-
public function testAfterGetMatchingProductIdsWithSimpleProduct()
64+
public function testAroundGetMatchingProductIdsWithSimpleProduct()
6565
{
6666
$this->configurableProductsProviderMock->expects($this->once())->method('getIds')->willReturn([]);
6767
$this->configurableMock->expects($this->never())->method('getChildrenIds');
68+
$this->ruleMock->expects($this->never())
69+
->method('setProductsFilter');
6870

6971
$productIds = ['product' => 'valid results'];
7072
$this->assertEquals(
7173
$productIds,
72-
$this->configurableProductHandler->afterGetMatchingProductIds($this->ruleMock, $productIds)
74+
$this->configurableProductHandler->aroundGetMatchingProductIds(
75+
$this->ruleMock,
76+
function () {
77+
return ['product' => 'valid results'];
78+
}
79+
)
7380
);
7481
}
7582

7683
/**
7784
* @return void
7885
*/
79-
public function testAfterGetMatchingProductIdsWithConfigurableProduct()
86+
public function testAroundGetMatchingProductIdsWithConfigurableProduct()
8087
{
8188
$this->configurableProductsProviderMock->expects($this->once())->method('getIds')
8289
->willReturn(['conf1', 'conf2']);
8390
$this->configurableMock->expects($this->any())->method('getChildrenIds')->willReturnMap([
8491
['conf1', true, [ 0 => ['simple1']]],
8592
['conf2', true, [ 0 => ['simple1', 'simple2']]],
8693
]);
94+
$this->ruleMock->expects($this->never())
95+
->method('setProductsFilter');
8796

8897
$this->assertEquals(
8998
[
@@ -96,21 +105,118 @@ public function testAfterGetMatchingProductIdsWithConfigurableProduct()
96105
3 => true,
97106
]
98107
],
99-
$this->configurableProductHandler->afterGetMatchingProductIds(
108+
$this->configurableProductHandler->aroundGetMatchingProductIds(
100109
$this->ruleMock,
101-
[
102-
'conf1' => [
103-
0 => true,
104-
1 => true,
105-
],
106-
'conf2' => [
107-
0 => false,
108-
1 => false,
109-
3 => true,
110-
4 => false,
111-
],
112-
]
110+
function () {
111+
return [
112+
'conf1' => [
113+
0 => true,
114+
1 => true,
115+
],
116+
'conf2' => [
117+
0 => false,
118+
1 => false,
119+
3 => true,
120+
4 => false,
121+
],
122+
];
123+
}
113124
)
114125
);
115126
}
127+
128+
/**
129+
* @param array $productsFilter
130+
* @param array $expectedProductsFilter
131+
* @param array $matchingProductIds
132+
* @param array $expectedMatchingProductIds
133+
* @return void
134+
* @dataProvider aroundGetMatchingProductIdsDataProvider
135+
*/
136+
public function testAroundGetMatchingProductIdsWithProductsFilter(
137+
array $productsFilter,
138+
array $expectedProductsFilter,
139+
array $matchingProductIds,
140+
array $expectedMatchingProductIds
141+
): void {
142+
$configurableProducts = [
143+
'conf1' => ['simple11', 'simple12'],
144+
'conf2' => ['simple21', 'simple22'],
145+
];
146+
$this->configurableProductsProviderMock->method('getIds')
147+
->willReturnCallback(
148+
function ($ids) use ($configurableProducts) {
149+
return array_intersect($ids, array_keys($configurableProducts));
150+
}
151+
);
152+
$this->configurableMock->method('getChildrenIds')
153+
->willReturnCallback(
154+
function ($id) use ($configurableProducts) {
155+
return [0 => $configurableProducts[$id] ?? []];
156+
}
157+
);
158+
159+
$this->configurableMock->method('getParentIdsByChild')
160+
->willReturnCallback(
161+
function ($ids) use ($configurableProducts) {
162+
$result = [];
163+
foreach ($configurableProducts as $configurableProduct => $childProducts) {
164+
if (array_intersect($ids, $childProducts)) {
165+
$result[] = $configurableProduct;
166+
}
167+
}
168+
return $result;
169+
}
170+
);
171+
172+
$this->ruleMock->method('getProductsFilter')
173+
->willReturn($productsFilter);
174+
175+
$this->ruleMock->expects($this->once())
176+
->method('setProductsFilter')
177+
->willReturn($expectedProductsFilter);
178+
179+
$this->assertEquals(
180+
$expectedMatchingProductIds,
181+
$this->configurableProductHandler->aroundGetMatchingProductIds(
182+
$this->ruleMock,
183+
function () use ($matchingProductIds) {
184+
return $matchingProductIds;
185+
}
186+
)
187+
);
188+
}
189+
190+
/**
191+
* @return array[]
192+
*/
193+
public function aroundGetMatchingProductIdsDataProvider(): array
194+
{
195+
return [
196+
[
197+
['simple1',],
198+
['simple1',],
199+
['simple1' => [1 => false]],
200+
['simple1' => [1 => false],],
201+
],
202+
[
203+
['simple11',],
204+
['simple11', 'conf1',],
205+
['simple11' => [1 => false], 'conf1' => [1 => true],],
206+
['simple11' => [1 => true],],
207+
],
208+
[
209+
['simple11', 'simple12',],
210+
['simple11', 'conf1',],
211+
['simple11' => [1 => false], 'conf1' => [1 => true],],
212+
['simple11' => [1 => true], 'simple12' => [1 => true],],
213+
],
214+
[
215+
['conf1', 'simple11', 'simple12'],
216+
['conf1', 'simple11', 'simple12'],
217+
['conf1' => [1 => true], 'simple11' => [1 => false], 'simple12' => [1 => false]],
218+
['simple11' => [1 => true], 'simple12' => [1 => true]],
219+
],
220+
];
221+
}
116222
}

dev/tests/integration/testsuite/Magento/CatalogRuleConfigurable/Model/Indexer/Product/ProductRuleIndexerTest.php

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,51 +49,109 @@ protected function setUp(): void
4949
}
5050

5151
/**
52+
* @dataProvider productsDataProvider
53+
* @param string $reindexSku
54+
* @param array $expectedPrices
5255
* @return void
56+
* @throws \Magento\Framework\Exception\NoSuchEntityException
5357
*/
54-
public function testExecute(): void
58+
public function testExecute(string $reindexSku, array $expectedPrices): void
5559
{
56-
$product = $this->productRepository->get('configurable');
60+
$product = $this->productRepository->get($reindexSku);
5761
$this->productRuleIndexer->execute([$product->getId()]);
5862

59-
$product = $this->productRepository->get('simple_10');
60-
$price = $this->getCatalogRulePrice($product);
61-
$this->assertEquals(5, $price);
63+
$this->assertEquals($expectedPrices, $this->getCatalogRulePrices(array_keys($expectedPrices)));
6264
}
6365

6466
/**
67+
* @dataProvider productsDataProvider
68+
* @param string $reindexSku
69+
* @param array $expectedPrices
6570
* @return void
71+
* @throws \Magento\Framework\Exception\LocalizedException
72+
* @throws \Magento\Framework\Exception\NoSuchEntityException
6673
*/
67-
public function testExecuteRow(): void
74+
public function testExecuteRow(string $reindexSku, array $expectedPrices): void
6875
{
69-
$product = $this->productRepository->get('configurable');
76+
$product = $this->productRepository->get($reindexSku);
7077
$this->productRuleIndexer->executeRow($product->getId());
7178

72-
$product = $this->productRepository->get('simple_10');
73-
$price = $this->getCatalogRulePrice($product);
74-
$this->assertEquals(5, $price);
79+
$this->assertEquals($expectedPrices, $this->getCatalogRulePrices(array_keys($expectedPrices)));
7580
}
7681

7782
/**
83+
* @dataProvider productsDataProvider
84+
* @param string $reindexSku
85+
* @param array $expectedPrices
7886
* @return void
87+
* @throws \Magento\Framework\Exception\LocalizedException
88+
* @throws \Magento\Framework\Exception\NoSuchEntityException
7989
*/
80-
public function testExecuteList(): void
90+
public function testExecuteList(string $reindexSku, array $expectedPrices): void
8191
{
82-
$product = $this->productRepository->get('configurable');
92+
$product = $this->productRepository->get($reindexSku);
8393
$this->productRuleIndexer->executeList([$product->getId()]);
8494

85-
$product = $this->productRepository->get('simple_10');
86-
$price = $this->getCatalogRulePrice($product);
87-
$this->assertEquals(5, $price);
95+
$this->assertEquals($expectedPrices, $this->getCatalogRulePrices(array_keys($expectedPrices)));
8896
}
8997

98+
/**
99+
* @return void
100+
*/
90101
public function testExecuteFull(): void
91102
{
92103
$this->productRuleIndexer->executeFull();
93104

94-
$product = $this->productRepository->get('simple_10');
95-
$price = $this->getCatalogRulePrice($product);
96-
$this->assertEquals(5, $price);
105+
$expectedPrices = [
106+
'simple_10' => 5,
107+
'simple_20' => 10,
108+
];
109+
$this->assertEquals($expectedPrices, $this->getCatalogRulePrices(array_keys($expectedPrices)));
110+
}
111+
112+
/**
113+
* @return array
114+
*/
115+
public function productsDataProvider(): array
116+
{
117+
return [
118+
[
119+
'configurable',
120+
[
121+
'simple_10' => 5,
122+
'simple_20' => 10,
123+
]
124+
],
125+
[
126+
'simple_10',
127+
[
128+
'simple_10' => 5,
129+
'simple_20' => 10,
130+
]
131+
],
132+
[
133+
'simple_20',
134+
[
135+
'simple_10' => 5,
136+
'simple_20' => 10,
137+
]
138+
],
139+
];
140+
}
141+
142+
/**
143+
* @param array $skus
144+
* @return array
145+
* @throws \Magento\Framework\Exception\NoSuchEntityException
146+
*/
147+
private function getCatalogRulePrices(array $skus): array
148+
{
149+
$actualPrices = [];
150+
foreach ($skus as $sku) {
151+
$product = $this->productRepository->get($sku);
152+
$actualPrices[$sku] = $this->getCatalogRulePrice($product);
153+
}
154+
return $actualPrices;
97155
}
98156

99157
/**

0 commit comments

Comments
 (0)