Skip to content

Commit

Permalink
Merge pull request #6525 from magento-tsg-csl3/2.4-develop-pr50
Browse files Browse the repository at this point in the history
[TSG-CSL3] For 2.4 (pr50)
  • Loading branch information
zakdma authored Jan 22, 2021
2 parents 00a70ec + 146a85f commit 30301a5
Show file tree
Hide file tree
Showing 25 changed files with 627 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -916,7 +916,12 @@ public function addWebsiteFilter($websites = null)
}

$this->_productLimitationFilters['website_ids'] = $websites;
$this->_applyProductLimitations();

if ($this->getStoreId() == Store::DEFAULT_STORE_ID) {
$this->_productLimitationJoinWebsite();
} else {
$this->_applyProductLimitations();
}

return $this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Framework\Validator\UniversalFactory;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -93,6 +94,11 @@ class CollectionTest extends TestCase
*/
private $storeManager;

/**
* @var ProductLimitation|MockObject
*/
private $productLimitationMock;

/**
* @var EntityFactory|MockObject
*/
Expand Down Expand Up @@ -192,7 +198,7 @@ protected function setUp(): void
$this->entityMock->expects($this->any())->method('getTable')->willReturnArgument(0);
$this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock);

$productLimitationMock = $this->createMock(
$this->productLimitationMock = $this->createMock(
ProductLimitation::class
);
$productLimitationFactoryMock = $this->getMockBuilder(
Expand All @@ -201,7 +207,7 @@ protected function setUp(): void
->setMethods(['create'])->getMock();

$productLimitationFactoryMock->method('create')
->willReturn($productLimitationMock);
->willReturn($this->productLimitationMock);
$this->collection = $this->objectManager->getObject(
Collection::class,
[
Expand Down Expand Up @@ -432,4 +438,44 @@ public function testGetNewEmptyItem()
$secondItem = $this->collection->getNewEmptyItem();
$this->assertEquals($firstItem, $secondItem);
}

/**
* Test to add website filter in admin area
*/
public function testAddWebsiteFilterOnAdminStore(): void
{
$websiteIds = [2];
$websiteTable = 'catalog_product_website';
$joinCondition = 'join condition';
$this->productLimitationMock->expects($this->atLeastOnce())
->method('offsetSet')
->with('website_ids', $websiteIds);
$this->productLimitationMock->method('offsetExists')
->with('website_ids')
->willReturn(true);
$this->productLimitationMock->method('offsetGet')
->with('website_ids')
->willReturn($websiteIds);
$this->connectionMock->expects($this->once())
->method('quoteInto')
->with('product_website.website_id IN(?)', $websiteIds, 'int')
->willReturn($joinCondition);
$this->selectMock->method('getPart')->with(Select::FROM)->willReturn([]);
/** @var AbstractEntity|MockObject $eavEntity */
$eavEntity = $this->createMock(AbstractEntity::class);
$eavEntity->method('getTable')
->with('catalog_product_website')
->willReturn($websiteTable);
$this->selectMock->expects($this->once())
->method('join')
->with(
['product_website' => $websiteTable],
'product_website.product_id = e.entity_id AND ' . $joinCondition,
[]
);

$this->collection->setEntity($eavEntity);
$this->collection->setStoreId(Store::DEFAULT_STORE_ID);
$this->collection->addWebsiteFilter($websiteIds);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ private function fetch() : array
$this->searchCriteriaBuilder->create(),
$this->attributeCodes,
false,
true
false
);

/** @var \Magento\Catalog\Model\Product $product */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public function getList(

$this->collectionPreProcessor->process($collection, $searchCriteria, $attributes, $context);

if (!$isChildSearch) {
if ($isChildSearch) {
$visibilityIds = $isSearch
? $this->visibility->getVisibleInSearchIds()
: $this->visibility->getVisibleInCatalogIds();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ private function deleteProductsLinks(
if (!empty($linksToDelete) && Import::BEHAVIOR_APPEND === $importEntity->getBehavior()) {
foreach ($linksToDelete as $linkTypeId => $productIds) {
if (!empty($productIds)) {
$whereLinkId = $importEntity->getConnection()->quoteInto('link_type_id', $linkTypeId);
$whereLinkId = $importEntity->getConnection()->quoteInto('link_type_id = ?', $linkTypeId);
$whereProductId = $importEntity->getConnection()->quoteInto(
'product_id IN (?)',
array_unique($productIds)
Expand Down
51 changes: 40 additions & 11 deletions app/code/Magento/CatalogRule/Model/Indexer/ReindexRuleProduct.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

namespace Magento\CatalogRule\Model\Indexer;

use Magento\CatalogRule\Model\Indexer\IndexerTableSwapperInterface as TableSwapper;
use Magento\Catalog\Model\ResourceModel\Indexer\ActiveTableSwitcher;
use Magento\CatalogRule\Model\Indexer\IndexerTableSwapperInterface as TableSwapper;
use Magento\CatalogRule\Model\Rule;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
Expand All @@ -18,6 +18,8 @@
*/
class ReindexRuleProduct
{
private const ADMIN_WEBSITE_ID = 0;

/**
* @var ResourceConnection
*/
Expand All @@ -38,22 +40,30 @@ class ReindexRuleProduct
*/
private $localeDate;

/**
* @var bool
*/
private $useWebsiteTimezone;

/**
* @param ResourceConnection $resource
* @param ActiveTableSwitcher $activeTableSwitcher
* @param TableSwapper $tableSwapper
* @param TimezoneInterface $localeDate
* @param bool $useWebsiteTimezone
*/
public function __construct(
ResourceConnection $resource,
ActiveTableSwitcher $activeTableSwitcher,
TableSwapper $tableSwapper,
TimezoneInterface $localeDate
TimezoneInterface $localeDate,
bool $useWebsiteTimezone = true
) {
$this->resource = $resource;
$this->activeTableSwitcher = $activeTableSwitcher;
$this->tableSwapper = $tableSwapper;
$this->localeDate = $localeDate;
$this->useWebsiteTimezone = $useWebsiteTimezone;
}

/**
Expand Down Expand Up @@ -95,18 +105,18 @@ public function execute(Rule $rule, $batchCount, $useAdditionalTable = false)
$actionOperator = $rule->getSimpleAction();
$actionAmount = $rule->getDiscountAmount();
$actionStop = $rule->getStopRulesProcessing();
$fromTimeInAdminTz = $this->parseDateByWebsiteTz((string)$rule->getFromDate(), self::ADMIN_WEBSITE_ID);
$toTimeInAdminTz = $this->parseDateByWebsiteTz((string)$rule->getToDate(), self::ADMIN_WEBSITE_ID);

$rows = [];
foreach ($websiteIds as $websiteId) {
$scopeTz = new \DateTimeZone(
$this->localeDate->getConfigTimezone(ScopeInterface::SCOPE_WEBSITE, $websiteId)
);
$fromTime = $rule->getFromDate()
? (new \DateTime($rule->getFromDate(), $scopeTz))->getTimestamp()
: 0;
$toTime = $rule->getToDate()
? (new \DateTime($rule->getToDate(), $scopeTz))->getTimestamp() + IndexBuilder::SECONDS_IN_DAY - 1
: 0;
$fromTime = $this->useWebsiteTimezone
? $this->parseDateByWebsiteTz((string)$rule->getFromDate(), (int)$websiteId)
: $fromTimeInAdminTz;
$toTime = $this->useWebsiteTimezone
? $this->parseDateByWebsiteTz((string)$rule->getToDate(), (int)$websiteId)
+ ($rule->getToDate() ? IndexBuilder::SECONDS_IN_DAY - 1 : 0)
: $toTimeInAdminTz;

foreach ($productIds as $productId => $validationByWebsite) {
if (empty($validationByWebsite[$websiteId])) {
Expand Down Expand Up @@ -140,4 +150,23 @@ public function execute(Rule $rule, $batchCount, $useAdditionalTable = false)

return true;
}

/**
* Parse date value by the timezone of the website
*
* @param string $date
* @param int $websiteId
* @return int
*/
private function parseDateByWebsiteTz(string $date, int $websiteId): int
{
if (empty($date)) {
return 0;
}

$websiteTz = $this->localeDate->getConfigTimezone(ScopeInterface::SCOPE_WEBSITE, $websiteId);
$dateTime = new \DateTime($date, new \DateTimeZone($websiteTz));

return $dateTime->getTimestamp();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
namespace Magento\CatalogRule\Model\Indexer;

use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;

/**
Expand Down Expand Up @@ -39,25 +40,33 @@ class ReindexRuleProductPrice
*/
private $pricesPersistor;

/**
* @var bool
*/
private $useWebsiteTimezone;

/**
* @param StoreManagerInterface $storeManager
* @param RuleProductsSelectBuilder $ruleProductsSelectBuilder
* @param ProductPriceCalculator $productPriceCalculator
* @param TimezoneInterface $localeDate
* @param RuleProductPricesPersistor $pricesPersistor
* @param bool $useWebsiteTimezone
*/
public function __construct(
StoreManagerInterface $storeManager,
RuleProductsSelectBuilder $ruleProductsSelectBuilder,
ProductPriceCalculator $productPriceCalculator,
TimezoneInterface $localeDate,
RuleProductPricesPersistor $pricesPersistor
RuleProductPricesPersistor $pricesPersistor,
bool $useWebsiteTimezone = true
) {
$this->storeManager = $storeManager;
$this->ruleProductsSelectBuilder = $ruleProductsSelectBuilder;
$this->productPriceCalculator = $productPriceCalculator;
$this->localeDate = $localeDate;
$this->pricesPersistor = $pricesPersistor;
$this->useWebsiteTimezone = $useWebsiteTimezone;
}

/**
Expand All @@ -82,11 +91,9 @@ public function execute(int $batchCount, ?int $productId = null, bool $useAdditi
$prevKey = null;

$storeGroup = $this->storeManager->getGroup($website->getDefaultGroupId());
$currentDate = $this->localeDate->scopeDate($storeGroup->getDefaultStoreId(), null, true);
$previousDate = (clone $currentDate)->modify('-1 day');
$previousDate->setTime(23, 59, 59);
$nextDate = (clone $currentDate)->modify('+1 day');
$nextDate->setTime(0, 0, 0);
$dateInterval = $this->useWebsiteTimezone
? $this->getDateInterval((int)$storeGroup->getDefaultStoreId())
: $this->getDateInterval(Store::DEFAULT_STORE_ID);

while ($ruleData = $productsStmt->fetch()) {
$ruleProductId = $ruleData['product_id'];
Expand All @@ -107,7 +114,7 @@ public function execute(int $batchCount, ?int $productId = null, bool $useAdditi
/**
* Build prices for each day
*/
foreach ([$previousDate, $currentDate, $nextDate] as $date) {
foreach ($dateInterval as $date) {
$time = $date->getTimestamp();
if (($ruleData['from_time'] == 0 ||
$time >= $ruleData['from_time']) && ($ruleData['to_time'] == 0 ||
Expand Down Expand Up @@ -157,4 +164,21 @@ public function execute(int $batchCount, ?int $productId = null, bool $useAdditi

return true;
}

/**
* Retrieve date sequence in store time zone
*
* @param int $storeId
* @return \DateTime[]
*/
private function getDateInterval(int $storeId): array
{
$currentDate = $this->localeDate->scopeDate($storeId, null, true);
$previousDate = (clone $currentDate)->modify('-1 day');
$previousDate->setTime(23, 59, 59);
$nextDate = (clone $currentDate)->modify('+1 day');
$nextDate->setTime(0, 0, 0);

return [$previousDate, $currentDate, $nextDate];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->

<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
<actionGroup name="SaveAndContinueEditCatalogPriceRuleActionGroup">
<annotations>
<description>Clicks on Save and Continue Edit. Validates that the Success Message is present and correct on the Admin Catalog Price Rule creation/edit page.</description>
</annotations>

<waitForElementVisible selector="{{AdminNewCatalogPriceRule.saveAndContinue}}" stepKey="waitForSaveAndContinueEditButton"/>
<click selector="{{AdminNewCatalogPriceRule.saveAndContinue}}" stepKey="saveAndContinueEdit"/>
<see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the rule." stepKey="assertSuccess"/>
</actionGroup>
</actionGroups>
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ protected function setUp(): void
$this->ruleProductsSelectBuilderMock,
$this->productPriceCalculatorMock,
$this->localeDate,
$this->pricesPersistorMock
$this->pricesPersistorMock,
true
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

class ReindexRuleProductTest extends TestCase
{
private const ADMIN_WEBSITE_ID = 0;

/**
* @var ReindexRuleProduct
*/
Expand Down Expand Up @@ -57,7 +59,8 @@ protected function setUp(): void
$this->resourceMock,
$this->activeTableSwitcherMock,
$this->tableSwapperMock,
$this->localeDateMock
$this->localeDateMock,
true
);
}

Expand Down Expand Up @@ -85,6 +88,7 @@ public function testExecuteIfRuleWithoutWebsiteIds()
public function testExecute()
{
$websiteId = 3;
$adminTimeZone = 'America/Chicago';
$websiteTz = 'America/Los_Angeles';
$productIds = [
4 => [$websiteId => 1],
Expand Down Expand Up @@ -123,10 +127,11 @@ public function testExecute()
$ruleMock->expects($this->once())->method('getDiscountAmount')->willReturn(43);
$ruleMock->expects($this->once())->method('getStopRulesProcessing')->willReturn(true);

$this->localeDateMock->expects($this->once())
->method('getConfigTimezone')
->with(ScopeInterface::SCOPE_WEBSITE, $websiteId)
->willReturn($websiteTz);
$this->localeDateMock->method('getConfigTimezone')
->willReturnMap([
[ScopeInterface::SCOPE_WEBSITE, self::ADMIN_WEBSITE_ID, $adminTimeZone],
[ScopeInterface::SCOPE_WEBSITE, $websiteId, $websiteTz],
]);

$batchRows = [
[
Expand Down
Loading

0 comments on commit 30301a5

Please sign in to comment.