|
11 | 11 | use Magento\CatalogRule\Api\Data\RuleInterface; |
12 | 12 | use Magento\CatalogRule\Model\Indexer\Rule\RuleProductProcessor; |
13 | 13 | use Magento\CatalogRule\Model\ResourceModel\RuleFactory as ResourceRuleFactory; |
| 14 | +use Magento\Framework\App\ResourceConnection; |
| 15 | +use Magento\Indexer\Model\Indexer; |
| 16 | +use Magento\ProductPriceDataExporter\Model\Query\DateWebsiteProvider; |
14 | 17 | use Magento\Framework\Exception\CouldNotSaveException; |
15 | 18 | use Magento\Framework\Exception\InputException; |
16 | 19 | use Magento\Framework\Exception\LocalizedException; |
@@ -119,6 +122,95 @@ public function testExportSimpleProductsWithDisabledCatalogPriceRulePrices(array |
119 | 122 | $this->checkExpectedItemsAreExportedInFeed($expectedSimpleProductPrices); |
120 | 123 | } |
121 | 124 |
|
| 125 | + /** |
| 126 | + * Catalog rule price must still be exported for a website whose local date differs from the |
| 127 | + * default scope date, when catalogrule_product_price holds only the default-scope date - the |
| 128 | + * state left by the indexer with useWebsiteTimezone=false (CatalogRuleStaging) after midnight |
| 129 | + * UTC for UTC-negative stores. |
| 130 | + * |
| 131 | + * The default scope timezone (Kiritimati, UTC+14) and the base store timezone (Pago_Pago, |
| 132 | + * UTC-11) are 25h apart, so the website-local date is always different from the default scope |
| 133 | + * date and the export has to fall back to the default scope date to find the rule price. |
| 134 | + * |
| 135 | + * getDefaultScopeDate() reads the timezone via store scope 0 (the admin store), so the |
| 136 | + * config fixture must also be applied to admin_store - a plain default-scope fixture only |
| 137 | + * patches the "default" config branch and leaves the admin store's cached value stale. |
| 138 | + * |
| 139 | + * @magentoConfigFixture general/locale/timezone Pacific/Kiritimati |
| 140 | + * @magentoConfigFixture admin_store general/locale/timezone Pacific/Kiritimati |
| 141 | + * @magentoConfigFixture default_store general/locale/timezone Pacific/Pago_Pago |
| 142 | + * @magentoDataFixture Magento_ProductPriceDataExporter::Test/_files/simple_products.php |
| 143 | + * @magentoDataFixture Magento/CatalogRule/_files/catalog_rule_25_customer_group_all.php |
| 144 | + * @throws NoSuchEntityException |
| 145 | + */ |
| 146 | + public function testExportCatalogRulePriceWhenWebsiteDateDiffersFromDefaultScope(): void |
| 147 | + { |
| 148 | + $objectManager = Bootstrap::getObjectManager(); |
| 149 | + $resourceConnection = $objectManager->get(ResourceConnection::class); |
| 150 | + $dateProvider = $objectManager->get(DateWebsiteProvider::class); |
| 151 | + |
| 152 | + $baseWebsiteId = (int)$this->websiteRepository->get('base')->getId(); |
| 153 | + $defaultScopeDate = $dateProvider->getDefaultScopeDate(); |
| 154 | + $websiteDate = $dateProvider->getWebsitesDate()[$baseWebsiteId] ?? null; |
| 155 | + |
| 156 | + // Guard the test premise: with a >24h timezone spread these must never be equal, |
| 157 | + // otherwise the default-scope fallback would not be exercised. |
| 158 | + self::assertNotSame( |
| 159 | + $defaultScopeDate, |
| 160 | + $websiteDate, |
| 161 | + 'Website local date must differ from the default scope date for this test to be meaningful' |
| 162 | + ); |
| 163 | + |
| 164 | + // Reproduce useWebsiteTimezone=false state: the rule price exists only under the |
| 165 | + // default-scope date, not under the base website's local date. |
| 166 | + $productId = (int)$this->productRepository->get('simple_product_with_regular_price')->getId(); |
| 167 | + $connection = $resourceConnection->getConnection(); |
| 168 | + $table = $resourceConnection->getTableName('catalogrule_product_price'); |
| 169 | + $connection->delete($table, ['product_id = ?' => $productId]); |
| 170 | + $connection->insert($table, [ |
| 171 | + 'rule_date' => $defaultScopeDate, |
| 172 | + 'customer_group_id' => 0, |
| 173 | + 'product_id' => $productId, |
| 174 | + 'rule_price' => self::getPriceForVersion(41.6625), |
| 175 | + 'website_id' => $baseWebsiteId, |
| 176 | + ]); |
| 177 | + |
| 178 | + // Force the price feed to be rebuilt from the manipulated rule price table. |
| 179 | + $feedIndexer = $objectManager->create(Indexer::class); |
| 180 | + $feedIndexer->load('catalog_data_exporter_product_prices'); |
| 181 | + $feedIndexer->invalidate(); |
| 182 | + |
| 183 | + $this->checkExpectedItemsAreExportedInFeed([ |
| 184 | + 'simple_product_with_regular_price_base_0' => [ |
| 185 | + 'sku' => 'simple_product_with_regular_price', |
| 186 | + 'type' => 'SIMPLE', |
| 187 | + 'customerGroupCode' => '0', |
| 188 | + 'websiteCode' => 'base', |
| 189 | + 'regular' => 55.55, |
| 190 | + 'discounts' => null, |
| 191 | + 'deleted' => false |
| 192 | + ], |
| 193 | + 'simple_product_with_regular_price_base_b6589fc6ab0dc82cf12099d1c2d40ab994e8410c' => [ |
| 194 | + 'sku' => 'simple_product_with_regular_price', |
| 195 | + 'type' => 'SIMPLE', |
| 196 | + 'customerGroupCode' => 'b6589fc6ab0dc82cf12099d1c2d40ab994e8410c', |
| 197 | + 'websiteCode' => 'base', |
| 198 | + 'regular' => 55.55, |
| 199 | + 'discounts' => [0 => ['code' => 'catalog_rule', 'price' => self::getPriceForVersion(41.6625)]], |
| 200 | + 'deleted' => false |
| 201 | + ], |
| 202 | + 'simple_product_with_regular_price_test_0' => [ |
| 203 | + 'sku' => 'simple_product_with_regular_price', |
| 204 | + 'type' => 'SIMPLE', |
| 205 | + 'customerGroupCode' => '0', |
| 206 | + 'websiteCode' => 'test', |
| 207 | + 'regular' => 55.55, |
| 208 | + 'discounts' => null, |
| 209 | + 'deleted' => false |
| 210 | + ], |
| 211 | + ]); |
| 212 | + } |
| 213 | + |
122 | 214 | /** |
123 | 215 | * @magentoDataFixture Magento_ProductPriceDataExporter::Test/_files/downloadable_products.php |
124 | 216 | * @param array $expectedDownloadableProductPricesDataProvider |
|
0 commit comments