Skip to content

Commit 6884b19

Browse files
authored
MDEE-854: Special price for bundle products being synced as final price instead of percentage. (#443)
* MDEE-854: Special price for bundle products being synced as final price instead of percentage.
1 parent 19b7238 commit 6884b19

File tree

5 files changed

+307
-223
lines changed

5 files changed

+307
-223
lines changed

ProductPriceDataExporter/Model/Provider/ProductPrice.php

Lines changed: 89 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use Magento\ProductPriceDataExporter\Model\Query\CustomerGroupPricesQuery;
3535
use Magento\ProductPriceDataExporter\Model\Query\ParentProductsQuery;
3636
use Magento\ProductPriceDataExporter\Model\Query\ProductPricesQuery;
37+
use Magento\Framework\DB\Select;
3738

3839
/**
3940
* Collect raw product prices: regular price and discounts: special price, customer group price, rule price, ...
@@ -73,14 +74,11 @@ class ProductPrice implements DataProcessorInterface
7374
private CommerceDataExportLoggerInterface $logger;
7475
private Config $eavConfig;
7576

76-
/**
77-
* @var array|null
78-
*/
7977
private ?array $priceAttributes = null;
8078

81-
private array|null $websitesByStore = null;
79+
private ?array $websitesByStore = null;
8280

83-
private array|null $websites = null;
81+
private ?array $websites = null;
8482

8583
/**
8684
* @var ParentProductsQuery
@@ -141,12 +139,47 @@ public function execute(
141139
$ids = array_column($arguments, 'productId');
142140
$productPriceTemplate = $this->getProductPriceTemplate($ids);
143141

144-
$cursor = $this->resourceConnection->getConnection()->query(
145-
$this->pricesQuery->getQuery($ids, $this->getPriceAttributes())
146-
);
147-
$pricesRawData = [];
148-
142+
$select = $this->pricesQuery->getQuery($ids, $this->getPriceAttributes());
149143
// update price template: set price if global price set, set bundle price type
144+
$pricesRawData = $this->updatePriceTemplate($select, $productPriceTemplate);
145+
146+
// build up fallback prices
147+
$fallbackPrices = $this->buildFallbackPrices($pricesRawData, $productPriceTemplate);
148+
149+
// add prices to fallback prices that were set only on global level
150+
foreach ($productPriceTemplate as $productId => $websites) {
151+
foreach ($websites as $websiteId => $productTemplate) {
152+
$key = $this->buildKey($productId, $websiteId, self::FALLBACK_CUSTOMER_GROUP);
153+
$fallbackPrices[$key] = $productTemplate;
154+
}
155+
}
156+
157+
$filteredIds = array_unique(array_column($fallbackPrices, 'productId'));
158+
// Add customer group prices to fallback records before processing
159+
$this->addFallbackCustomerGroupPrices($fallbackPrices, $filteredIds);
160+
161+
// process fallback prices
162+
$this->processFallbackPrices($fallbackPrices, $dataProcessorCallback, $metadata);
163+
164+
$this->addCustomerGroupPrices($fallbackPrices, $filteredIds, $dataProcessorCallback, $metadata);
165+
}
166+
167+
/**
168+
* Update price template
169+
*
170+
* @param Select $select
171+
* @param array $productPriceTemplate
172+
* @return array
173+
* @throws LocalizedException
174+
* @throws UnableRetrieveData
175+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
176+
* @SuppressWarnings(PHPMD.NPathComplexity)
177+
*/
178+
private function updatePriceTemplate(Select $select, array &$productPriceTemplate): array
179+
{
180+
$cursor = $this->resourceConnection->getConnection()->query($select);
181+
182+
$pricesRawData = [];
150183
while ($row = $cursor->fetch()) {
151184
$percentageDiscount = null;
152185
$productId = $row['entity_id'];
@@ -191,9 +224,22 @@ public function execute(
191224
}
192225
}
193226
}
227+
return $pricesRawData;
228+
}
194229

230+
/**
231+
* Build fallback prices for each product and website combination
232+
*
233+
* @param array $pricesRawData
234+
* @param array $productPriceTemplate
235+
* @return array
236+
* @throws LocalizedException
237+
* @throws UnableRetrieveData
238+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
239+
*/
240+
private function buildFallbackPrices(array $pricesRawData, array &$productPriceTemplate): array
241+
{
195242
$fallbackPrices = [];
196-
197243
// build up fallback prices
198244
foreach ($pricesRawData as $row) {
199245
$percentageDiscount = null;
@@ -224,31 +270,40 @@ public function execute(
224270
if ($this->shouldOverrideGlobalPrice($fallbackPrices[$key], self::REGULAR_PRICE, $row)) {
225271
$fallbackPrices[$key][self::REGULAR_PRICE] = (float)$price;
226272
}
227-
} else {
228-
if ($this->shouldOverrideGlobalPrice($fallbackPrices[$key], $attributeCode, $row)) {
229-
if ($price === null) {
230-
// cover case when special price was set on global level but unset on store level
231-
$fallbackPrices[$key]['discounts'] = [];
232-
} else {
233-
$this->addDiscountPrice($fallbackPrices[$key], $attributeCode, $price, $percentageDiscount);
273+
} elseif ($this->shouldOverrideGlobalPrice($fallbackPrices[$key], $attributeCode, $row)) {
274+
if ($price === null) {
275+
// cover case when special price was set on global level but unset on store level
276+
$fallbackPrices[$key]['discounts'] = [];
277+
} else {
278+
if ($attributeCode === 'special_price'
279+
&& \in_array(
280+
$fallbackPrices[$key]['type'],
281+
[self::BUNDLE_DYNAMIC, self::BUNDLE_FIXED],
282+
true
283+
)) {
284+
$percentageDiscount = $price;
234285
}
286+
$this->addDiscountPrice($fallbackPrices[$key], $attributeCode, $price, $percentageDiscount);
235287
}
236288
}
237289
}
238290
}
291+
return $fallbackPrices;
292+
}
239293

240-
// add prices to fallback prices that were set only on global level
241-
foreach ($productPriceTemplate as $productId => $websites) {
242-
foreach ($websites as $websiteId => $productTemplate) {
243-
$key = $this->buildKey($productId, $websiteId, self::FALLBACK_CUSTOMER_GROUP);
244-
$fallbackPrices[$key] = $productTemplate;
245-
}
246-
}
247-
248-
$filteredIds = array_unique(array_column($fallbackPrices, 'productId'));
249-
// Add customer group prices to fallback records before processing
250-
$this->addFallbackCustomerGroupPrices($fallbackPrices, $filteredIds);
251-
294+
/**
295+
* Process fallback prices in batches
296+
*
297+
* @param array $fallbackPrices
298+
* @param callable $dataProcessorCallback
299+
* @param FeedIndexMetadata $metadata
300+
* @return void
301+
*/
302+
private function processFallbackPrices(
303+
array $fallbackPrices,
304+
callable $dataProcessorCallback,
305+
FeedIndexMetadata $metadata
306+
): void {
252307
$itemN = 0;
253308
$prices = [];
254309
foreach ($fallbackPrices as $fallbackPrice) {
@@ -262,8 +317,6 @@ public function execute(
262317
if ($prices) {
263318
$dataProcessorCallback($this->get($prices));
264319
}
265-
266-
$this->addCustomerGroupPrices($fallbackPrices, $filteredIds, $dataProcessorCallback, $metadata);
267320
}
268321

269322
/**
@@ -373,6 +426,7 @@ private function getProductPriceTemplate(
373426

374427
/**
375428
* SQL query may return multiple rows for the same product but with different price per price attribute.
429+
*
376430
* Website-specific price must override global price
377431
*
378432
* @param array $fallbackPrice
@@ -578,6 +632,8 @@ private function addDiscountPrice(
578632
}
579633

580634
/**
635+
* Get Parent Product Skus by product ids
636+
*
581637
* @param array $productIds
582638
* @return array
583639
* @throws \Zend_Db_Statement_Exception
@@ -606,7 +662,7 @@ private function getParentProductSkus(array $productIds): array
606662
*/
607663
private function convertProductType(string $typeId): string
608664
{
609-
$productType = in_array($typeId, self::PRODUCT_TYPE, true) ? $typeId : Type::TYPE_SIMPLE;
665+
$productType = \in_array($typeId, self::PRODUCT_TYPE, true) ? $typeId : Type::TYPE_SIMPLE;
610666

611667
return strtoupper($productType);
612668
}

0 commit comments

Comments
 (0)