Skip to content

Commit b4eeb82

Browse files
committed
ACP2E-165: [Magento Cloud] min_price and max_price DB values are set to non-zero when configurable product stock status is Out Of Stock and child products are Out Of Stock and Disabled
1 parent 4e14a82 commit b4eeb82

File tree

7 files changed

+179
-87
lines changed

7 files changed

+179
-87
lines changed

app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php

Lines changed: 8 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
1111
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\BasePriceModifier;
12-
use Magento\Framework\DB\Select;
1312
use Magento\Framework\Indexer\DimensionalIndexerInterface;
1413
use Magento\Framework\EntityManager\MetadataPool;
1514
use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
@@ -18,7 +17,6 @@
1817
use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure;
1918
use Magento\Framework\App\Config\ScopeConfigInterface;
2019
use Magento\Framework\App\ObjectManager;
21-
use Magento\CatalogInventory\Model\Stock;
2220

2321
/**
2422
* Configurable Products Price Indexer Resource model
@@ -83,9 +81,9 @@ class Configurable implements DimensionalIndexerInterface
8381
private $baseSelectProcessor;
8482

8583
/**
86-
* @var PopulateIndexTableInterface
84+
* @var OptionsIndexerInterface
8785
*/
88-
private $populateOptionsIndexTable;
86+
private $optionsIndexer;
8987

9088
/**
9189
* @param BaseFinalPrice $baseFinalPrice
@@ -98,7 +96,7 @@ class Configurable implements DimensionalIndexerInterface
9896
* @param string $connectionName
9997
* @param ScopeConfigInterface|null $scopeConfig
10098
* @param BaseSelectProcessorInterface|null $baseSelectProcessor
101-
* @param PopulateIndexTableInterface|null $populateOptionsIndexTable
99+
* @param OptionsIndexerInterface|null $optionsIndexer
102100
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
103101
*/
104102
public function __construct(
@@ -112,7 +110,7 @@ public function __construct(
112110
$connectionName = 'indexer',
113111
ScopeConfigInterface $scopeConfig = null,
114112
?BaseSelectProcessorInterface $baseSelectProcessor = null,
115-
?PopulateIndexTableInterface $populateOptionsIndexTable = null
113+
?OptionsIndexerInterface $optionsIndexer = null
116114
) {
117115
$this->baseFinalPrice = $baseFinalPrice;
118116
$this->indexTableStructureFactory = $indexTableStructureFactory;
@@ -125,8 +123,8 @@ public function __construct(
125123
$this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class);
126124
$this->baseSelectProcessor = $baseSelectProcessor ?:
127125
ObjectManager::getInstance()->get(BaseSelectProcessorInterface::class);
128-
$this->populateOptionsIndexTable = $populateOptionsIndexTable
129-
?: ObjectManager::getInstance()->get(PopulateIndexTableInterface::class);
126+
$this->optionsIndexer = $optionsIndexer
127+
?: ObjectManager::getInstance()->get(OptionsIndexerInterface::class);
130128
}
131129

132130
/**
@@ -183,62 +181,15 @@ private function applyConfigurableOption(
183181
true
184182
);
185183

186-
$this->fillTemporaryOptionsTable($temporaryOptionsTableName, $dimensions, $entityIds);
184+
$indexTableName = $this->getMainTable($dimensions);
185+
$this->optionsIndexer->execute($indexTableName, $temporaryOptionsTableName, $entityIds);
187186
$this->updateTemporaryTable($temporaryPriceTable->getTableName(), $temporaryOptionsTableName);
188187

189188
$this->getConnection()->delete($temporaryOptionsTableName);
190189

191190
return $this;
192191
}
193192

194-
/**
195-
* Put data into catalog product price indexer config option temp table
196-
*
197-
* @param string $temporaryOptionsTableName
198-
* @param array $dimensions
199-
* @param array $entityIds
200-
*
201-
* @return void
202-
* @throws \Exception
203-
*/
204-
private function fillTemporaryOptionsTable(string $temporaryOptionsTableName, array $dimensions, array $entityIds)
205-
{
206-
$metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
207-
$linkField = $metadata->getLinkField();
208-
209-
$select = $this->getConnection()->select()->from(
210-
['i' => $this->getMainTable($dimensions)],
211-
[]
212-
)->join(
213-
['l' => $this->getTable('catalog_product_super_link')],
214-
'l.product_id = i.entity_id',
215-
[]
216-
)->join(
217-
['le' => $this->getTable('catalog_product_entity')],
218-
'le.' . $linkField . ' = l.parent_id',
219-
[]
220-
);
221-
222-
$this->baseSelectProcessor->process($select);
223-
224-
$select->columns(
225-
[
226-
'le.entity_id',
227-
'customer_group_id',
228-
'website_id',
229-
'MIN(final_price)',
230-
'MAX(final_price)',
231-
'MIN(tier_price)',
232-
]
233-
)->group(
234-
['le.entity_id', 'customer_group_id', 'website_id']
235-
);
236-
if ($entityIds !== null) {
237-
$select->where('le.entity_id IN (?)', $entityIds, \Zend_Db::INT_TYPE);
238-
}
239-
$this->populateOptionsIndexTable->execute($select, $temporaryOptionsTableName);
240-
}
241-
242193
/**
243194
* Update data in the catalog product price indexer temp table
244195
*
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,40 @@
88
namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price;
99

1010
use Magento\Catalog\Model\Indexer\Product\Price\TableMaintainer;
11-
use Magento\Framework\DB\Select;
1211

1312
/**
14-
* Populate index table with data from select
13+
* Configurable product options prices aggregator
1514
*/
16-
class PopulateIndexTable implements PopulateIndexTableInterface
15+
class OptionsIndexer implements OptionsIndexerInterface
1716
{
17+
/**
18+
* @var OptionsSelectBuilderInterface
19+
*/
20+
private $selectBuilder;
21+
1822
/**
1923
* @var TableMaintainer
2024
*/
2125
private $tableMaintainer;
2226

2327
/**
28+
* @param OptionsSelectBuilderInterface $selectBuilder
2429
* @param TableMaintainer $tableMaintainer
2530
*/
2631
public function __construct(
32+
OptionsSelectBuilderInterface $selectBuilder,
2733
TableMaintainer $tableMaintainer
2834
) {
35+
$this->selectBuilder = $selectBuilder;
2936
$this->tableMaintainer = $tableMaintainer;
3037
}
3138

3239
/**
3340
* @inheritdoc
3441
*/
35-
public function execute(Select $select, string $indexTableName): void
42+
public function execute(string $indexTable, string $tempIndexTable, ?array $entityIds = null): void
3643
{
37-
$this->tableMaintainer->insertFromSelect($select, $indexTableName, []);
44+
$select = $this->selectBuilder->execute($indexTable, $entityIds);
45+
$this->tableMaintainer->insertFromSelect($select, $tempIndexTable, []);
3846
}
3947
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price;
9+
10+
use Magento\Framework\DB\Select;
11+
12+
/**
13+
* Configurable product options prices aggregator
14+
*/
15+
interface OptionsIndexerInterface
16+
{
17+
/**
18+
* Aggregate configurable product options prices and save it in a temporary index table
19+
*
20+
* @param string $indexTable
21+
* @param string $tempIndexTable
22+
* @param array|null $entityIds
23+
*/
24+
public function execute(string $indexTable, string $tempIndexTable, ?array $entityIds = null): void;
25+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price;
9+
10+
use Magento\Catalog\Model\ResourceModel\Product\BaseSelectProcessorInterface;
11+
use Magento\Framework\App\ResourceConnection;
12+
use Magento\Framework\DB\Select;
13+
use Magento\Framework\EntityManager\MetadataPool;
14+
15+
/**
16+
* Build select for aggregating configurable product options prices
17+
*/
18+
class OptionsSelectBuilder implements OptionsSelectBuilderInterface
19+
{
20+
/**
21+
* @var MetadataPool
22+
*/
23+
private $metadataPool;
24+
25+
/**
26+
* @var ResourceConnection
27+
*/
28+
private $resourceConnection;
29+
30+
/**
31+
* @var string
32+
*/
33+
private $connectionName;
34+
35+
/**
36+
* @var BaseSelectProcessorInterface
37+
*/
38+
private $selectProcessor;
39+
40+
/**
41+
* @param BaseSelectProcessorInterface $selectProcessor
42+
* @param MetadataPool $metadataPool
43+
* @param ResourceConnection $resourceConnection
44+
* @param string $connectionName
45+
*/
46+
public function __construct(
47+
BaseSelectProcessorInterface $selectProcessor,
48+
MetadataPool $metadataPool,
49+
ResourceConnection $resourceConnection,
50+
string $connectionName = 'indexer'
51+
) {
52+
$this->selectProcessor = $selectProcessor;
53+
$this->metadataPool = $metadataPool;
54+
$this->resourceConnection = $resourceConnection;
55+
$this->connectionName = $connectionName;
56+
}
57+
58+
/**
59+
* @inheritdoc
60+
*/
61+
public function execute(string $indexTable, ?array $entityIds = null): Select
62+
{
63+
$connection = $this->resourceConnection->getConnection($this->connectionName);
64+
$metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
65+
$linkField = $metadata->getLinkField();
66+
67+
$select = $connection->select()
68+
->from(
69+
['i' => $indexTable],
70+
[]
71+
)
72+
->join(
73+
['l' => $this->resourceConnection->getTableName('catalog_product_super_link', $this->connectionName)],
74+
'l.product_id = i.entity_id',
75+
[]
76+
)
77+
->join(
78+
['le' => $this->resourceConnection->getTableName('catalog_product_entity', $this->connectionName)],
79+
'le.' . $linkField . ' = l.parent_id',
80+
[]
81+
);
82+
83+
$select->columns(
84+
[
85+
'le.entity_id',
86+
'customer_group_id',
87+
'website_id',
88+
'MIN(final_price)',
89+
'MAX(final_price)',
90+
'MIN(tier_price)',
91+
]
92+
)->group(
93+
['le.entity_id', 'customer_group_id', 'website_id']
94+
);
95+
if ($entityIds !== null) {
96+
$select->where('le.entity_id IN (?)', $entityIds, \Zend_Db::INT_TYPE);
97+
}
98+
return $this->selectProcessor->process($select);
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price;
9+
10+
use Magento\Framework\DB\Select;
11+
12+
/**
13+
* Aggregate configurable product options prices and save it in a temporary index table
14+
*/
15+
interface OptionsSelectBuilderInterface
16+
{
17+
/**
18+
* Return select with aggregated configurable product options prices
19+
*
20+
* @param string $indexTable
21+
* @param array|null $entityIds
22+
* @return Select
23+
*/
24+
public function execute(string $indexTable, ?array $entityIds = null): Select;
25+
}

app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/PopulateIndexTableInterface.php

Lines changed: 0 additions & 24 deletions
This file was deleted.

app/code/Magento/ConfigurableProduct/etc/di.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
<preference for="Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProviderInterface" type="Magento\ConfigurableProduct\Pricing\Price\LowestPriceOptionsProvider" />
1818
<preference for="Magento\ConfigurableProduct\Model\AttributeOptionProviderInterface" type="Magento\ConfigurableProduct\Model\AttributeOptionProvider" />
1919
<preference for="Magento\ConfigurableProduct\Model\ResourceModel\Attribute\OptionSelectBuilderInterface" type="Magento\ConfigurableProduct\Model\ResourceModel\Attribute\OptionSelectBuilder" />
20-
<preference for="Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\PopulateIndexTableInterface" type="\Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\PopulateIndexTable" />
20+
<preference for="Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\OptionsIndexerInterface" type="\Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\OptionsIndexer" />
21+
<preference for="Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\OptionsSelectBuilderInterface" type="\Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\OptionsSelectBuilder" />
2122

2223
<type name="Magento\CatalogInventory\Model\Quote\Item\QuantityValidator\Initializer\Option">
2324
<plugin name="configurable_product" type="Magento\ConfigurableProduct\Model\Quote\Item\QuantityValidator\Initializer\Option\Plugin\ConfigurableProduct" sortOrder="50" />
@@ -209,6 +210,12 @@
209210
<argument name="baseSelectProcessor" xsi:type="object">Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\BaseStockStatusSelectProcessor</argument>
210211
</arguments>
211212
</type>
213+
<type name="Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\OptionsSelectBuilder">
214+
<arguments>
215+
<argument name="selectProcessor" xsi:type="object">Magento\ConfigurableProduct\Model\ResourceModel\Product\Indexer\Price\BaseStockStatusSelectProcessor</argument>
216+
<argument name="connectionName" xsi:type="string">indexer</argument>
217+
</arguments>
218+
</type>
212219
<type name="Magento\ConfigurableProduct\Plugin\Model\ResourceModel\Product">
213220
<arguments>
214221
<argument name="productIndexer" xsi:type="object">Magento\Catalog\Model\Indexer\Product\Full</argument>

0 commit comments

Comments
 (0)