Skip to content

Commit 8a51300

Browse files
committed
AC-10847: As low as label is still displayed for a Configurable Product for the Test case AC-6158
1 parent c9f1b34 commit 8a51300

File tree

1 file changed

+66
-12
lines changed

1 file changed

+66
-12
lines changed

app/code/Magento/ConfigurableProduct/Pricing/Price/ConfigurableRegularPrice.php

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Magento\ConfigurableProduct\Pricing\Price;
88

99
use Magento\Catalog\Model\Product;
10+
use Magento\ConfigurableProduct\Model\ConfigurableMaxPriceCalculator;
1011
use Magento\Framework\App\ObjectManager;
1112
use Magento\Framework\ObjectManager\ResetAfterRequestInterface;
1213
use Magento\Framework\Pricing\Price\AbstractPrice;
@@ -54,12 +55,23 @@ class ConfigurableRegularPrice extends AbstractPrice implements
5455
*/
5556
private $lowestPriceOptionsProvider;
5657

58+
/**
59+
* @var ConfigurableMaxPriceCalculator
60+
*/
61+
private $configurableMaxPriceCalculator;
62+
63+
/**
64+
* @var array<int, bool>
65+
*/
66+
private $equalFinalPriceCache = [];
67+
5768
/**
5869
* @param \Magento\Framework\Pricing\SaleableInterface $saleableItem
5970
* @param float $quantity
6071
* @param \Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator
6172
* @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
6273
* @param PriceResolverInterface $priceResolver
74+
* @param ConfigurableMaxPriceCalculator $configurableMaxPriceCalculator
6375
* @param LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider
6476
*/
6577
public function __construct(
@@ -68,12 +80,14 @@ public function __construct(
6880
\Magento\Framework\Pricing\Adjustment\CalculatorInterface $calculator,
6981
\Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
7082
PriceResolverInterface $priceResolver,
83+
ConfigurableMaxPriceCalculator $configurableMaxPriceCalculator,
7184
?LowestPriceOptionsProviderInterface $lowestPriceOptionsProvider = null
7285
) {
7386
parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
7487
$this->priceResolver = $priceResolver;
7588
$this->lowestPriceOptionsProvider = $lowestPriceOptionsProvider ?:
7689
ObjectManager::getInstance()->get(LowestPriceOptionsProviderInterface::class);
90+
$this->configurableMaxPriceCalculator = $configurableMaxPriceCalculator;
7791
}
7892

7993
/**
@@ -184,31 +198,71 @@ private function getConfigurableOptionsProvider()
184198
public function _resetState(): void
185199
{
186200
$this->values = [];
201+
$this->equalFinalPriceCache = [];
187202
}
188203

189204
/**
190-
* Check whether Configurable Product has more than one child product and if their prices are equal
205+
* Check whether Configurable Product have more than one children products
191206
*
192207
* @param SaleableInterface $product
193208
* @return bool
209+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
210+
* @SuppressWarnings(PHPMD.NPathComplexity)
194211
*/
195212
public function isChildProductsOfEqualPrices(SaleableInterface $product): bool
196213
{
197-
// Get all child products of the configurable product
198-
$childProducts = $product->getTypeInstance()->getUsedProducts($product);
199-
if (count($childProducts) <= 1) {
200-
return false; // Not more than one child product
214+
$storeId = (int) ($product->getStoreId() ?: 0);
215+
$cacheKey = (int) $product->getId() . ':' . $storeId;
216+
if (isset($this->equalFinalPriceCache[$cacheKey])) {
217+
return $this->equalFinalPriceCache[$cacheKey];
218+
}
219+
220+
$memoKey = '_children_final_prices_equal_store_' . $storeId;
221+
$memoized = $product->getData($memoKey);
222+
if ($memoized !== null) {
223+
return (bool) $memoized;
201224
}
202225

203-
$prices = [];
204-
foreach ($childProducts as $child) {
205-
$prices[] = $child->getFinalPrice();
226+
// Listing fast-path: if index fields are present, rely on them and avoid any child loading
227+
$minIndexed = $product->getData('minimal_price');
228+
$maxIndexed = $product->getData('max_price');
229+
if (is_numeric($minIndexed) && is_numeric($maxIndexed)) {
230+
$result = ((float)$minIndexed === (float)$maxIndexed);
231+
$this->equalFinalPriceCache[$cacheKey] = $result;
232+
$product->setData($memoKey, $result);
233+
return $result;
206234
}
207235

208-
$minPrice = min($prices);
209-
$maxPrice = max($prices);
236+
$children = $product->getTypeInstance()->getUsedProducts($product);
237+
$firstFinal = null;
238+
$saleableChildrenCount = 0;
239+
$allEqual = true;
240+
foreach ($children as $child) {
241+
if (!$child->isSalable()) {
242+
continue;
243+
}
244+
$saleableChildrenCount++;
245+
$value = $child->getPriceInfo()->getPrice('final_price')->getAmount()->getValue();
246+
if ($firstFinal === null) {
247+
$firstFinal = $value;
248+
continue;
249+
}
250+
if ($value != $firstFinal) {
251+
$allEqual = false;
252+
break;
253+
}
254+
}
255+
256+
if ($saleableChildrenCount <= 1 || $firstFinal === null || !$allEqual) {
257+
$product->setData($memoKey, false);
258+
$this->equalFinalPriceCache[$cacheKey] = false;
259+
return false;
260+
}
210261

211-
// Return true only if all child prices are equal (min == max)
212-
return $minPrice == $maxPrice;
262+
// Guard against parent-level extra discounts (compute only when children are equal)
263+
$result = !($product->getFinalPrice() < $firstFinal);
264+
$this->equalFinalPriceCache[$cacheKey] = $result;
265+
$product->setData($memoKey, $result);
266+
return $result;
213267
}
214268
}

0 commit comments

Comments
 (0)