34
34
use Magento \ProductPriceDataExporter \Model \Query \CustomerGroupPricesQuery ;
35
35
use Magento \ProductPriceDataExporter \Model \Query \ParentProductsQuery ;
36
36
use Magento \ProductPriceDataExporter \Model \Query \ProductPricesQuery ;
37
+ use Magento \Framework \DB \Select ;
37
38
38
39
/**
39
40
* Collect raw product prices: regular price and discounts: special price, customer group price, rule price, ...
@@ -73,14 +74,11 @@ class ProductPrice implements DataProcessorInterface
73
74
private CommerceDataExportLoggerInterface $ logger ;
74
75
private Config $ eavConfig ;
75
76
76
- /**
77
- * @var array|null
78
- */
79
77
private ?array $ priceAttributes = null ;
80
78
81
- private array | null $ websitesByStore = null ;
79
+ private ? array $ websitesByStore = null ;
82
80
83
- private array | null $ websites = null ;
81
+ private ? array $ websites = null ;
84
82
85
83
/**
86
84
* @var ParentProductsQuery
@@ -141,12 +139,47 @@ public function execute(
141
139
$ ids = array_column ($ arguments , 'productId ' );
142
140
$ productPriceTemplate = $ this ->getProductPriceTemplate ($ ids );
143
141
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 ());
149
143
// 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 = [];
150
183
while ($ row = $ cursor ->fetch ()) {
151
184
$ percentageDiscount = null ;
152
185
$ productId = $ row ['entity_id ' ];
@@ -191,9 +224,22 @@ public function execute(
191
224
}
192
225
}
193
226
}
227
+ return $ pricesRawData ;
228
+ }
194
229
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
+ {
195
242
$ fallbackPrices = [];
196
-
197
243
// build up fallback prices
198
244
foreach ($ pricesRawData as $ row ) {
199
245
$ percentageDiscount = null ;
@@ -224,31 +270,40 @@ public function execute(
224
270
if ($ this ->shouldOverrideGlobalPrice ($ fallbackPrices [$ key ], self ::REGULAR_PRICE , $ row )) {
225
271
$ fallbackPrices [$ key ][self ::REGULAR_PRICE ] = (float )$ price ;
226
272
}
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 ;
234
285
}
286
+ $ this ->addDiscountPrice ($ fallbackPrices [$ key ], $ attributeCode , $ price , $ percentageDiscount );
235
287
}
236
288
}
237
289
}
238
290
}
291
+ return $ fallbackPrices ;
292
+ }
239
293
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 {
252
307
$ itemN = 0 ;
253
308
$ prices = [];
254
309
foreach ($ fallbackPrices as $ fallbackPrice ) {
@@ -262,8 +317,6 @@ public function execute(
262
317
if ($ prices ) {
263
318
$ dataProcessorCallback ($ this ->get ($ prices ));
264
319
}
265
-
266
- $ this ->addCustomerGroupPrices ($ fallbackPrices , $ filteredIds , $ dataProcessorCallback , $ metadata );
267
320
}
268
321
269
322
/**
@@ -373,6 +426,7 @@ private function getProductPriceTemplate(
373
426
374
427
/**
375
428
* SQL query may return multiple rows for the same product but with different price per price attribute.
429
+ *
376
430
* Website-specific price must override global price
377
431
*
378
432
* @param array $fallbackPrice
@@ -578,6 +632,8 @@ private function addDiscountPrice(
578
632
}
579
633
580
634
/**
635
+ * Get Parent Product Skus by product ids
636
+ *
581
637
* @param array $productIds
582
638
* @return array
583
639
* @throws \Zend_Db_Statement_Exception
@@ -606,7 +662,7 @@ private function getParentProductSkus(array $productIds): array
606
662
*/
607
663
private function convertProductType (string $ typeId ): string
608
664
{
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 ;
610
666
611
667
return strtoupper ($ productType );
612
668
}
0 commit comments