Skip to content

Commit 19916b6

Browse files
ENGCOM-8785: Scheduled price rule time zone correction #28973
2 parents 2babf97 + b23165a commit 19916b6

File tree

5 files changed

+240
-39
lines changed

5 files changed

+240
-39
lines changed

app/code/Magento/CatalogRule/Model/Indexer/IndexBuilder.php

Lines changed: 64 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,23 @@
77
namespace Magento\CatalogRule\Model\Indexer;
88

99
use Magento\Catalog\Model\Product;
10+
use Magento\Catalog\Model\ProductFactory;
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;
1014
use Magento\CatalogRule\Model\ResourceModel\Rule\Collection as RuleCollection;
1115
use Magento\CatalogRule\Model\ResourceModel\Rule\CollectionFactory as RuleCollectionFactory;
1216
use Magento\CatalogRule\Model\Rule;
17+
use Magento\Eav\Model\Config;
1318
use Magento\Framework\App\ObjectManager;
19+
use Magento\Framework\App\ResourceConnection;
20+
use Magento\Framework\Exception\LocalizedException;
1421
use Magento\Framework\Pricing\PriceCurrencyInterface;
15-
use Magento\CatalogRule\Model\Indexer\IndexBuilder\ProductLoader;
16-
use Magento\CatalogRule\Model\Indexer\IndexerTableSwapperInterface as TableSwapper;
22+
use Magento\Framework\Stdlib\DateTime;
23+
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
24+
use Magento\Store\Model\ScopeInterface;
25+
use Magento\Store\Model\StoreManagerInterface;
26+
use Psr\Log\LoggerInterface;
1727

1828
/**
1929
* Catalog rule index builder
@@ -46,12 +56,12 @@ class IndexBuilder
4656
protected $_catalogRuleGroupWebsiteColumnsList = ['rule_id', 'customer_group_id', 'website_id'];
4757

4858
/**
49-
* @var \Magento\Framework\App\ResourceConnection
59+
* @var ResourceConnection
5060
*/
5161
protected $resource;
5262

5363
/**
54-
* @var \Magento\Store\Model\StoreManagerInterface
64+
* @var StoreManagerInterface
5565
*/
5666
protected $storeManager;
5767

@@ -61,7 +71,7 @@ class IndexBuilder
6171
protected $ruleCollectionFactory;
6272

6373
/**
64-
* @var \Psr\Log\LoggerInterface
74+
* @var LoggerInterface
6575
*/
6676
protected $logger;
6777

@@ -71,22 +81,22 @@ class IndexBuilder
7181
protected $priceCurrency;
7282

7383
/**
74-
* @var \Magento\Eav\Model\Config
84+
* @var Config
7585
*/
7686
protected $eavConfig;
7787

7888
/**
79-
* @var \Magento\Framework\Stdlib\DateTime
89+
* @var DateTime
8090
*/
8191
protected $dateFormat;
8292

8393
/**
84-
* @var \Magento\Framework\Stdlib\DateTime\DateTime
94+
* @var DateTime\DateTime
8595
*/
8696
protected $dateTime;
8797

8898
/**
89-
* @var \Magento\Catalog\Model\ProductFactory
99+
* @var ProductFactory
90100
*/
91101
protected $productFactory;
92102

@@ -136,7 +146,12 @@ class IndexBuilder
136146
private $pricesPersistor;
137147

138148
/**
139-
* @var \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher
149+
* @var TimezoneInterface|mixed
150+
*/
151+
private $localeDate;
152+
153+
/**
154+
* @var ActiveTableSwitcher|mixed
140155
*/
141156
private $activeTableSwitcher;
142157

@@ -146,52 +161,55 @@ class IndexBuilder
146161
private $tableSwapper;
147162

148163
/**
149-
* @var ProductLoader
164+
* @var ProductLoader|mixed
150165
*/
151166
private $productLoader;
152167

153168
/**
154169
* @param RuleCollectionFactory $ruleCollectionFactory
155170
* @param PriceCurrencyInterface $priceCurrency
156-
* @param \Magento\Framework\App\ResourceConnection $resource
157-
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
158-
* @param \Psr\Log\LoggerInterface $logger
159-
* @param \Magento\Eav\Model\Config $eavConfig
160-
* @param \Magento\Framework\Stdlib\DateTime $dateFormat
161-
* @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime
162-
* @param \Magento\Catalog\Model\ProductFactory $productFactory
171+
* @param ResourceConnection $resource
172+
* @param StoreManagerInterface $storeManager
173+
* @param LoggerInterface $logger
174+
* @param Config $eavConfig
175+
* @param DateTime $dateFormat
176+
* @param DateTime\DateTime $dateTime
177+
* @param ProductFactory $productFactory
163178
* @param int $batchCount
164179
* @param ProductPriceCalculator|null $productPriceCalculator
165180
* @param ReindexRuleProduct|null $reindexRuleProduct
166181
* @param ReindexRuleGroupWebsite|null $reindexRuleGroupWebsite
167182
* @param RuleProductsSelectBuilder|null $ruleProductsSelectBuilder
168183
* @param ReindexRuleProductPrice|null $reindexRuleProductPrice
169184
* @param RuleProductPricesPersistor|null $pricesPersistor
170-
* @param \Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher|null $activeTableSwitcher
185+
* @param ActiveTableSwitcher|null $activeTableSwitcher
171186
* @param ProductLoader|null $productLoader
172187
* @param TableSwapper|null $tableSwapper
188+
* @param TimezoneInterface|null $localeDate
173189
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
190+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
174191
*/
175192
public function __construct(
176193
RuleCollectionFactory $ruleCollectionFactory,
177194
PriceCurrencyInterface $priceCurrency,
178-
\Magento\Framework\App\ResourceConnection $resource,
179-
\Magento\Store\Model\StoreManagerInterface $storeManager,
180-
\Psr\Log\LoggerInterface $logger,
181-
\Magento\Eav\Model\Config $eavConfig,
182-
\Magento\Framework\Stdlib\DateTime $dateFormat,
183-
\Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
184-
\Magento\Catalog\Model\ProductFactory $productFactory,
195+
ResourceConnection $resource,
196+
StoreManagerInterface $storeManager,
197+
LoggerInterface $logger,
198+
Config $eavConfig,
199+
DateTime $dateFormat,
200+
DateTime\DateTime $dateTime,
201+
ProductFactory $productFactory,
185202
$batchCount = 1000,
186203
ProductPriceCalculator $productPriceCalculator = null,
187204
ReindexRuleProduct $reindexRuleProduct = null,
188205
ReindexRuleGroupWebsite $reindexRuleGroupWebsite = null,
189206
RuleProductsSelectBuilder $ruleProductsSelectBuilder = null,
190207
ReindexRuleProductPrice $reindexRuleProductPrice = null,
191208
RuleProductPricesPersistor $pricesPersistor = null,
192-
\Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher $activeTableSwitcher = null,
209+
ActiveTableSwitcher $activeTableSwitcher = null,
193210
ProductLoader $productLoader = null,
194-
TableSwapper $tableSwapper = null
211+
TableSwapper $tableSwapper = null,
212+
TimezoneInterface $localeDate = null
195213
) {
196214
$this->resource = $resource;
197215
$this->connection = $resource->getConnection();
@@ -224,19 +242,22 @@ public function __construct(
224242
RuleProductPricesPersistor::class
225243
);
226244
$this->activeTableSwitcher = $activeTableSwitcher ?? ObjectManager::getInstance()->get(
227-
\Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher::class
245+
ActiveTableSwitcher::class
228246
);
229247
$this->productLoader = $productLoader ?? ObjectManager::getInstance()->get(
230248
ProductLoader::class
231249
);
232250
$this->tableSwapper = $tableSwapper ??
233251
ObjectManager::getInstance()->get(TableSwapper::class);
252+
$this->localeDate = $localeDate ??
253+
ObjectManager::getInstance()->get(TimezoneInterface::class);
234254
}
235255

236256
/**
237257
* Reindex by id
238258
*
239259
* @param int $id
260+
* @throws LocalizedException
240261
* @return void
241262
* @api
242263
*/
@@ -254,7 +275,7 @@ public function reindexById($id)
254275
$this->reindexRuleGroupWebsite->execute();
255276
} catch (\Exception $e) {
256277
$this->critical($e);
257-
throw new \Magento\Framework\Exception\LocalizedException(
278+
throw new LocalizedException(
258279
__('Catalog rule indexing failed. See details in exception log.')
259280
);
260281
}
@@ -264,7 +285,7 @@ public function reindexById($id)
264285
* Reindex by ids
265286
*
266287
* @param array $ids
267-
* @throws \Magento\Framework\Exception\LocalizedException
288+
* @throws LocalizedException
268289
* @return void
269290
* @api
270291
*/
@@ -274,7 +295,7 @@ public function reindexByIds(array $ids)
274295
$this->doReindexByIds($ids);
275296
} catch (\Exception $e) {
276297
$this->critical($e);
277-
throw new \Magento\Framework\Exception\LocalizedException(
298+
throw new LocalizedException(
278299
__("Catalog rule indexing failed. See details in exception log.")
279300
);
280301
}
@@ -308,7 +329,7 @@ protected function doReindexByIds($ids)
308329
/**
309330
* Full reindex
310331
*
311-
* @throws \Magento\Framework\Exception\LocalizedException
332+
* @throws LocalizedException
312333
* @return void
313334
* @api
314335
*/
@@ -318,7 +339,7 @@ public function reindexFull()
318339
$this->doReindexFull();
319340
} catch (\Exception $e) {
320341
$this->critical($e);
321-
throw new \Magento\Framework\Exception\LocalizedException(
342+
throw new LocalizedException(
322343
__("Catalog rule indexing failed. See details in exception log.")
323344
);
324345
}
@@ -404,16 +425,22 @@ private function assignProductToRule(Rule $rule, int $productEntityId, array $we
404425
);
405426

406427
$customerGroupIds = $rule->getCustomerGroupIds();
407-
$fromTime = strtotime($rule->getFromDate());
408-
$toTime = strtotime($rule->getToDate());
409-
$toTime = $toTime ? $toTime + self::SECONDS_IN_DAY - 1 : 0;
410428
$sortOrder = (int)$rule->getSortOrder();
411429
$actionOperator = $rule->getSimpleAction();
412430
$actionAmount = $rule->getDiscountAmount();
413431
$actionStop = $rule->getStopRulesProcessing();
414432

415433
$rows = [];
416434
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;
417444
foreach ($customerGroupIds as $customerGroupId) {
418445
$rows[] = [
419446
'rule_id' => $ruleId,

dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/IndexerBuilderTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
namespace Magento\CatalogRule\Model\Indexer;
77

8+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Store\Model\StoreManagerInterface;
810
use Magento\TestFramework\Helper\Bootstrap;
911

1012
class IndexerBuilderTest extends \PHPUnit\Framework\TestCase
@@ -34,13 +36,25 @@ class IndexerBuilderTest extends \PHPUnit\Framework\TestCase
3436
*/
3537
protected $productThird;
3638

39+
/**
40+
* @var StoreManagerInterface
41+
*/
42+
private $storeManager;
43+
44+
/**
45+
* @var ProductRepositoryInterface
46+
*/
47+
private $productRepository;
48+
3749
protected function setUp(): void
3850
{
3951
$this->indexerBuilder = Bootstrap::getObjectManager()->get(
4052
\Magento\CatalogRule\Model\Indexer\IndexBuilder::class
4153
);
4254
$this->resourceRule = Bootstrap::getObjectManager()->get(\Magento\CatalogRule\Model\ResourceModel\Rule::class);
4355
$this->product = Bootstrap::getObjectManager()->get(\Magento\Catalog\Model\Product::class);
56+
$this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
57+
$this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
4458
}
4559

4660
protected function tearDown(): void
@@ -82,6 +96,34 @@ public function testReindexById()
8296
$this->assertEquals(9.8, $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $product->getId()));
8397
}
8498

99+
/**
100+
* @magentoDbIsolation disabled
101+
* @magentoAppIsolation enabled
102+
* @magentoDataFixture Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off_tomorrow.php
103+
* @magentoConfigFixture base_website general/locale/timezone Europe/Amsterdam
104+
* @magentoConfigFixture general/locale/timezone America/Chicago
105+
*/
106+
public function testReindexByIdDifferentTimezones()
107+
{
108+
$productId = $this->productRepository->get('simple')->getId();
109+
$this->indexerBuilder->reindexById($productId);
110+
111+
$mainWebsiteId = $this->storeManager->getWebsite('base')->getId();
112+
$secondWebsiteId = $this->storeManager->getWebsite('test')->getId();
113+
$rawTimestamp = (new \DateTime('+1 day'))->getTimestamp();
114+
$timestamp = $rawTimestamp - ($rawTimestamp % (60 * 60 * 24));
115+
$mainWebsiteActiveRules =
116+
$this->resourceRule->getRulesFromProduct($timestamp, $mainWebsiteId, 1, $productId);
117+
$secondWebsiteActiveRules =
118+
$this->resourceRule->getRulesFromProduct($timestamp, $secondWebsiteId, 1, $productId);
119+
120+
$this->assertCount(1, $mainWebsiteActiveRules);
121+
// Avoid failure when staging is enabled as it removes catalog rule timestamp.
122+
if ((int)$mainWebsiteActiveRules[0]['from_time'] !== 0) {
123+
$this->assertCount(0, $secondWebsiteActiveRules);
124+
}
125+
}
126+
85127
/**
86128
* @magentoDbIsolation disabled
87129
* @magentoAppIsolation enabled

dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/Product/PriceTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class PriceTest extends \PHPUnit\Framework\TestCase
2121
* @var \Magento\Framework\ObjectManagerInterface
2222
*/
2323
private $objectManager;
24+
2425
/**
2526
* @var Rule
2627
*/
@@ -102,8 +103,8 @@ public function testPriceForSecondStore():void
102103
);
103104
$this->indexerBuilder->reindexById($simpleProduct->getId());
104105
$this->assertEquals(
105-
$this->resourceRule->getRulePrice(new \DateTime(), $websiteId, 1, $simpleProduct->getId()),
106-
25
106+
25,
107+
$this->resourceRule->getRulePrice(new \DateTime(), $websiteId, 1, $simpleProduct->getId())
107108
);
108109
}
109110

0 commit comments

Comments
 (0)