9
9
use Magento \Catalog \Model \Product ;
10
10
use Magento \Catalog \Model \ProductFactory ;
11
11
use Magento \Catalog \Model \ResourceModel \Indexer \ActiveTableSwitcher ;
12
+ use Magento \CatalogRule \Model \Indexer \IndexBuilder \ProductLoader ;
13
+ use Magento \CatalogRule \Model \Indexer \IndexerTableSwapperInterface as TableSwapper ;
12
14
use Magento \CatalogRule \Model \ResourceModel \Rule \Collection as RuleCollection ;
13
15
use Magento \CatalogRule \Model \ResourceModel \Rule \CollectionFactory as RuleCollectionFactory ;
14
16
use Magento \CatalogRule \Model \Rule ;
17
19
use Magento \Framework \App \ResourceConnection ;
18
20
use Magento \Framework \Exception \LocalizedException ;
19
21
use Magento \Framework \Pricing \PriceCurrencyInterface ;
20
- use Magento \CatalogRule \Model \Indexer \IndexBuilder \ProductLoader ;
21
- use Magento \CatalogRule \Model \Indexer \IndexerTableSwapperInterface as TableSwapper ;
22
22
use Magento \Framework \Stdlib \DateTime ;
23
+ use Magento \Framework \Stdlib \DateTime \TimezoneInterface ;
24
+ use Magento \Store \Model \ScopeInterface ;
23
25
use Magento \Store \Model \StoreManagerInterface ;
24
26
use Psr \Log \LoggerInterface ;
25
27
@@ -143,11 +145,26 @@ class IndexBuilder
143
145
*/
144
146
private $ pricesPersistor ;
145
147
148
+ /**
149
+ * @var TimezoneInterface|mixed
150
+ */
151
+ private $ localeDate ;
152
+
153
+ /**
154
+ * @var ActiveTableSwitcher|mixed
155
+ */
156
+ private $ activeTableSwitcher ;
157
+
146
158
/**
147
159
* @var TableSwapper
148
160
*/
149
161
private $ tableSwapper ;
150
162
163
+ /**
164
+ * @var ProductLoader|mixed
165
+ */
166
+ private $ productLoader ;
167
+
151
168
/**
152
169
* @param RuleCollectionFactory $ruleCollectionFactory
153
170
* @param PriceCurrencyInterface $priceCurrency
@@ -168,6 +185,7 @@ class IndexBuilder
168
185
* @param ActiveTableSwitcher|null $activeTableSwitcher
169
186
* @param ProductLoader|null $productLoader
170
187
* @param TableSwapper|null $tableSwapper
188
+ * @param TimezoneInterface|null $localeDate
171
189
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
172
190
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
173
191
*/
@@ -190,7 +208,8 @@ public function __construct(
190
208
RuleProductPricesPersistor $ pricesPersistor = null ,
191
209
ActiveTableSwitcher $ activeTableSwitcher = null ,
192
210
ProductLoader $ productLoader = null ,
193
- TableSwapper $ tableSwapper = null
211
+ TableSwapper $ tableSwapper = null ,
212
+ TimezoneInterface $ localeDate = null
194
213
) {
195
214
$ this ->resource = $ resource ;
196
215
$ this ->connection = $ resource ->getConnection ();
@@ -222,8 +241,16 @@ public function __construct(
222
241
$ this ->pricesPersistor = $ pricesPersistor ?? ObjectManager::getInstance ()->get (
223
242
RuleProductPricesPersistor::class
224
243
);
244
+ $ this ->activeTableSwitcher = $ activeTableSwitcher ?? ObjectManager::getInstance ()->get (
245
+ ActiveTableSwitcher::class
246
+ );
247
+ $ this ->productLoader = $ productLoader ?? ObjectManager::getInstance ()->get (
248
+ ProductLoader::class
249
+ );
225
250
$ this ->tableSwapper = $ tableSwapper ??
226
251
ObjectManager::getInstance ()->get (TableSwapper::class);
252
+ $ this ->localeDate = $ localeDate ??
253
+ ObjectManager::getInstance ()->get (TimezoneInterface::class);
227
254
}
228
255
229
256
/**
@@ -237,11 +264,19 @@ public function __construct(
237
264
public function reindexById ($ id )
238
265
{
239
266
try {
240
- $ this ->doReindexByIds ([$ id ]);
267
+ $ this ->cleanProductIndex ([$ id ]);
268
+
269
+ $ products = $ this ->productLoader ->getProducts ([$ id ]);
270
+ $ activeRules = $ this ->getActiveRules ();
271
+ foreach ($ products as $ product ) {
272
+ $ this ->applyRules ($ activeRules , $ product );
273
+ }
274
+
275
+ $ this ->reindexRuleGroupWebsite ->execute ();
241
276
} catch (\Exception $ e ) {
242
277
$ this ->critical ($ e );
243
278
throw new LocalizedException (
244
- __ (" Catalog rule indexing failed. See details in exception log. " )
279
+ __ (' Catalog rule indexing failed. See details in exception log. ' )
245
280
);
246
281
}
247
282
}
@@ -369,6 +404,68 @@ protected function cleanByIds($productIds)
369
404
$ this ->cleanProductPriceIndex ($ productIds );
370
405
}
371
406
407
+ /**
408
+ * Assign product to rule
409
+ *
410
+ * @param Rule $rule
411
+ * @param int $productEntityId
412
+ * @param array $websiteIds
413
+ * @return void
414
+ */
415
+ private function assignProductToRule (Rule $ rule , int $ productEntityId , array $ websiteIds ): void
416
+ {
417
+ $ ruleId = (int ) $ rule ->getId ();
418
+ $ ruleProductTable = $ this ->getTable ('catalogrule_product ' );
419
+ $ this ->connection ->delete (
420
+ $ ruleProductTable ,
421
+ [
422
+ 'rule_id = ? ' => $ ruleId ,
423
+ 'product_id = ? ' => $ productEntityId ,
424
+ ]
425
+ );
426
+
427
+ $ customerGroupIds = $ rule ->getCustomerGroupIds ();
428
+ $ sortOrder = (int )$ rule ->getSortOrder ();
429
+ $ actionOperator = $ rule ->getSimpleAction ();
430
+ $ actionAmount = $ rule ->getDiscountAmount ();
431
+ $ actionStop = $ rule ->getStopRulesProcessing ();
432
+
433
+ $ rows = [];
434
+ foreach ($ websiteIds as $ websiteId ) {
435
+ $ scopeTz = new \DateTimeZone (
436
+ $ this ->localeDate ->getConfigTimezone (ScopeInterface::SCOPE_WEBSITE , $ websiteId )
437
+ );
438
+ $ fromTime = $ rule ->getFromDate ()
439
+ ? (new \DateTime ($ rule ->getFromDate (), $ scopeTz ))->getTimestamp ()
440
+ : 0 ;
441
+ $ toTime = $ rule ->getToDate ()
442
+ ? (new \DateTime ($ rule ->getToDate (), $ scopeTz ))->getTimestamp () + IndexBuilder::SECONDS_IN_DAY - 1
443
+ : 0 ;
444
+ foreach ($ customerGroupIds as $ customerGroupId ) {
445
+ $ rows [] = [
446
+ 'rule_id ' => $ ruleId ,
447
+ 'from_time ' => $ fromTime ,
448
+ 'to_time ' => $ toTime ,
449
+ 'website_id ' => $ websiteId ,
450
+ 'customer_group_id ' => $ customerGroupId ,
451
+ 'product_id ' => $ productEntityId ,
452
+ 'action_operator ' => $ actionOperator ,
453
+ 'action_amount ' => $ actionAmount ,
454
+ 'action_stop ' => $ actionStop ,
455
+ 'sort_order ' => $ sortOrder ,
456
+ ];
457
+
458
+ if (count ($ rows ) == $ this ->batchCount ) {
459
+ $ this ->connection ->insertMultiple ($ ruleProductTable , $ rows );
460
+ $ rows = [];
461
+ }
462
+ }
463
+ }
464
+ if ($ rows ) {
465
+ $ this ->connection ->insertMultiple ($ ruleProductTable , $ rows );
466
+ }
467
+ }
468
+
372
469
/**
373
470
* Apply rule
374
471
*
@@ -392,6 +489,28 @@ protected function applyRule(Rule $rule, $product)
392
489
return $ this ;
393
490
}
394
491
492
+ /**
493
+ * Apply rules
494
+ *
495
+ * @param RuleCollection $ruleCollection
496
+ * @param Product $product
497
+ * @return void
498
+ */
499
+ private function applyRules (RuleCollection $ ruleCollection , Product $ product ): void
500
+ {
501
+ foreach ($ ruleCollection as $ rule ) {
502
+ if (!$ rule ->validate ($ product )) {
503
+ continue ;
504
+ }
505
+
506
+ $ websiteIds = array_intersect ($ product ->getWebsiteIds (), $ rule ->getWebsiteIds ());
507
+ $ this ->assignProductToRule ($ rule , $ product ->getId (), $ websiteIds );
508
+ }
509
+
510
+ $ this ->cleanProductPriceIndex ([$ product ->getId ()]);
511
+ $ this ->reindexRuleProductPrice ->execute ($ this ->batchCount , $ product ->getId ());
512
+ }
513
+
395
514
/**
396
515
* Retrieve table name
397
516
*
0 commit comments