-
+
= $block->getFieldHtml() ?>
- getAdditionalDescription()) : ?>
+ getAdditionalDescription()): ?>
= $block->escapeHtml($_message) ?>
@@ -42,4 +46,22 @@ $fieldCssClass .= $block->isRequired() ? ' required' : '';
"Magento_Customer/js/validation": {}
}
}
-
+
+
+
+
+});
+code;
+?>
+= /* @noEscape */ $secureRenderer->renderTag('script', [], $scriptString, false) ?>
diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php
index fa2ae669cc89d..a098325c820d6 100644
--- a/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php
+++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/ResetPassword.php
@@ -118,7 +118,7 @@ public function resolve(
$args['newPassword']
);
} catch (LocalizedException $e) {
- throw new GraphQlInputException(__('Cannot set the customer\'s password'), $e);
+ throw new GraphQlInputException(__($e->getMessage()), $e);
}
}
}
diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php
index f15f920fe95f4..0c3be73ec5047 100644
--- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php
+++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php
@@ -525,12 +525,12 @@ public function validateData()
protected function _importData()
{
//Preparing data for mass validation/import.
- $rows = [[]];
+ $rows = [];
while ($bunch = $this->_dataSourceModel->getNextBunch()) {
$rows[] = $bunch;
}
- $this->prepareCustomerData(array_merge(...$rows));
+ $this->prepareCustomerData(array_merge([], ...$rows));
unset($bunch, $rows);
$this->_dataSourceModel->getIterator()->rewind();
diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
index 5ebf242bd6ac4..2a02205bdc7e5 100644
--- a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
+++ b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php
@@ -514,8 +514,8 @@ protected function _importData()
{
while ($bunch = $this->_dataSourceModel->getNextBunch()) {
$this->prepareCustomerData($bunch);
- $entitiesToCreate = [[]];
- $entitiesToUpdate = [[]];
+ $entitiesToCreate = [];
+ $entitiesToUpdate = [];
$entitiesToDelete = [];
$attributesToSave = [];
@@ -549,8 +549,8 @@ protected function _importData()
}
}
- $entitiesToCreate = array_merge(...$entitiesToCreate);
- $entitiesToUpdate = array_merge(...$entitiesToUpdate);
+ $entitiesToCreate = array_merge([], ...$entitiesToCreate);
+ $entitiesToUpdate = array_merge([], ...$entitiesToUpdate);
$this->updateItemsCounterStats($entitiesToCreate, $entitiesToUpdate, $entitiesToDelete);
/**
diff --git a/app/code/Magento/Deploy/Console/Command/App/ConfigImportCommand.php b/app/code/Magento/Deploy/Console/Command/App/ConfigImportCommand.php
index 8a75ad0def222..eb87a9c12125b 100644
--- a/app/code/Magento/Deploy/Console/Command/App/ConfigImportCommand.php
+++ b/app/code/Magento/Deploy/Console/Command/App/ConfigImportCommand.php
@@ -3,14 +3,21 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+
namespace Magento\Deploy\Console\Command\App;
+use Magento\Config\Console\Command\EmulatedAdminhtmlAreaProcessor;
+use Magento\Deploy\Console\Command\App\ConfigImport\Processor;
+use Magento\Framework\App\Area;
+use Magento\Framework\App\AreaList;
+use Magento\Framework\App\DeploymentConfig;
+use Magento\Framework\App\ObjectManager;
+use Magento\Framework\Console\Cli;
+use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\RuntimeException;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-use Magento\Framework\Console\Cli;
-use Magento\Deploy\Console\Command\App\ConfigImport\Processor;
/**
* Runs the process of importing configuration data from shared source to appropriate application sources
@@ -21,9 +28,6 @@
*/
class ConfigImportCommand extends Command
{
- /**
- * Command name.
- */
const COMMAND_NAME = 'app:config:import';
/**
@@ -33,12 +37,40 @@ class ConfigImportCommand extends Command
*/
private $processor;
+ /**
+ * @var EmulatedAdminhtmlAreaProcessor
+ */
+ private $adminhtmlAreaProcessor;
+
+ /**
+ * @var DeploymentConfig
+ */
+ private $deploymentConfig;
+
+ /**
+ * @var AreaList
+ */
+ private $areaList;
+
/**
* @param Processor $processor the configuration importer
+ * @param DeploymentConfig|null $deploymentConfig
+ * @param EmulatedAdminhtmlAreaProcessor|null $adminhtmlAreaProcessor
+ * @param AreaList|null $areaList
*/
- public function __construct(Processor $processor)
- {
+ public function __construct(
+ Processor $processor,
+ DeploymentConfig $deploymentConfig = null,
+ EmulatedAdminhtmlAreaProcessor $adminhtmlAreaProcessor = null,
+ AreaList $areaList = null
+ ) {
$this->processor = $processor;
+ $this->deploymentConfig = $deploymentConfig
+ ?? ObjectManager::getInstance()->get(DeploymentConfig::class);
+ $this->adminhtmlAreaProcessor = $adminhtmlAreaProcessor
+ ?? ObjectManager::getInstance()->get(EmulatedAdminhtmlAreaProcessor::class);
+ $this->areaList = $areaList
+ ?? ObjectManager::getInstance()->get(AreaList::class);
parent::__construct();
}
@@ -55,12 +87,26 @@ protected function configure()
}
/**
- * Imports data from deployment configuration files to the DB. {@inheritdoc}
+ * Imports data from deployment configuration files to the DB.
+ * {@inheritdoc}
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return int
+ * @throws \Exception
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
try {
- $this->processor->execute($input, $output);
+ if ($this->canEmulateAdminhtmlArea()) {
+ // Emulate adminhtml area in order to execute all needed plugins declared only for this area
+ // For instance URL rewrite generation during creating store view
+ $this->adminhtmlAreaProcessor->process(function () use ($input, $output) {
+ $this->processor->execute($input, $output);
+ });
+ } else {
+ $this->processor->execute($input, $output);
+ }
} catch (RuntimeException $e) {
$output->writeln('
' . $e->getMessage() . '');
@@ -69,4 +115,19 @@ protected function execute(InputInterface $input, OutputInterface $output)
return Cli::RETURN_SUCCESS;
}
+
+ /**
+ * Detects if we can emulate adminhtml area
+ *
+ * This area could be not available for instance during setup:install
+ *
+ * @return bool
+ * @throws RuntimeException
+ * @throws FileSystemException
+ */
+ private function canEmulateAdminhtmlArea(): bool
+ {
+ return $this->deploymentConfig->isAvailable()
+ && in_array(Area::AREA_ADMINHTML, $this->areaList->getCodes());
+ }
}
diff --git a/app/code/Magento/Deploy/Package/Package.php b/app/code/Magento/Deploy/Package/Package.php
index 2a83d0d4c56ec..5780b46365680 100644
--- a/app/code/Magento/Deploy/Package/Package.php
+++ b/app/code/Magento/Deploy/Package/Package.php
@@ -443,11 +443,11 @@ public function getResultMap()
*/
public function getParentMap()
{
- $map = [[]];
+ $map = [];
foreach ($this->getParentPackages() as $parentPackage) {
$map[] = $parentPackage->getMap();
}
- return array_merge(...$map);
+ return array_merge([], ...$map);
}
/**
@@ -458,7 +458,7 @@ public function getParentMap()
*/
public function getParentFiles($type = null)
{
- $files = [[]];
+ $files = [];
foreach ($this->getParentPackages() as $parentPackage) {
if ($type === null) {
$files[] = $parentPackage->getFiles();
@@ -466,7 +466,7 @@ public function getParentFiles($type = null)
$files[] = $parentPackage->getFilesByType($type);
}
}
- return array_merge(...$files);
+ return array_merge([], ...$files);
}
/**
@@ -535,7 +535,7 @@ private function collectParentPaths(
$area,
$theme,
$locale,
- array & $result = [],
+ array &$result = [],
ThemeInterface $themeModel = null
) {
if (($package->getArea() != $area) || ($package->getTheme() != $theme) || ($package->getLocale() != $locale)) {
diff --git a/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImportCommandTest.php b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImportCommandTest.php
index da790a19f480a..32bdd63ef4638 100644
--- a/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImportCommandTest.php
+++ b/app/code/Magento/Deploy/Test/Unit/Console/Command/App/ConfigImportCommandTest.php
@@ -7,8 +7,11 @@
namespace Magento\Deploy\Test\Unit\Console\Command\App;
+use Magento\Config\Console\Command\EmulatedAdminhtmlAreaProcessor;
use Magento\Deploy\Console\Command\App\ConfigImport\Processor;
use Magento\Deploy\Console\Command\App\ConfigImportCommand;
+use Magento\Framework\App\AreaList;
+use Magento\Framework\App\DeploymentConfig;
use Magento\Framework\Console\Cli;
use Magento\Framework\Exception\RuntimeException;
use PHPUnit\Framework\MockObject\MockObject;
@@ -27,16 +30,37 @@ class ConfigImportCommandTest extends TestCase
*/
private $commandTester;
+ /**
+ * @var DeploymentConfig|MockObject
+ */
+ private $deploymentConfigMock;
+
+ /**
+ * @var EmulatedAdminhtmlAreaProcessor|MockObject
+ */
+ private $adminhtmlAreaProcessorMock;
+
+ /**
+ * @var AreaList|MockObject
+ */
+ private $areaListMock;
+
/**
* @return void
*/
protected function setUp(): void
{
- $this->processorMock = $this->getMockBuilder(Processor::class)
- ->disableOriginalConstructor()
- ->getMock();
+ $this->processorMock = $this->createMock(Processor::class);
+ $this->deploymentConfigMock = $this->createMock(DeploymentConfig::class);
+ $this->adminhtmlAreaProcessorMock = $this->createMock(EmulatedAdminhtmlAreaProcessor::class);
+ $this->areaListMock = $this->createMock(AreaList::class);
- $configImportCommand = new ConfigImportCommand($this->processorMock);
+ $configImportCommand = new ConfigImportCommand(
+ $this->processorMock,
+ $this->deploymentConfigMock,
+ $this->adminhtmlAreaProcessorMock,
+ $this->areaListMock
+ );
$this->commandTester = new CommandTester($configImportCommand);
}
@@ -46,6 +70,13 @@ protected function setUp(): void
*/
public function testExecute()
{
+ $this->deploymentConfigMock->expects($this->once())->method('isAvailable')->willReturn(true);
+ $this->adminhtmlAreaProcessorMock->expects($this->once())
+ ->method('process')->willReturnCallback(function (callable $callback, array $params = []) {
+ return $callback(...$params);
+ });
+ $this->areaListMock->expects($this->once())->method('getCodes')->willReturn(['adminhtml']);
+
$this->processorMock->expects($this->once())
->method('execute');
@@ -57,6 +88,13 @@ public function testExecute()
*/
public function testExecuteWithException()
{
+ $this->deploymentConfigMock->expects($this->once())->method('isAvailable')->willReturn(true);
+ $this->adminhtmlAreaProcessorMock->expects($this->once())
+ ->method('process')->willReturnCallback(function (callable $callback, array $params = []) {
+ return $callback(...$params);
+ });
+ $this->areaListMock->expects($this->once())->method('getCodes')->willReturn(['adminhtml']);
+
$this->processorMock->expects($this->once())
->method('execute')
->willThrowException(new RuntimeException(__('Some error')));
@@ -64,4 +102,34 @@ public function testExecuteWithException()
$this->assertSame(Cli::RETURN_FAILURE, $this->commandTester->execute([]));
$this->assertStringContainsString('Some error', $this->commandTester->getDisplay());
}
+
+ /**
+ * @return void
+ */
+ public function testExecuteWithDeploymentConfigNotAvailable()
+ {
+ $this->deploymentConfigMock->expects($this->once())->method('isAvailable')->willReturn(false);
+ $this->adminhtmlAreaProcessorMock->expects($this->never())->method('process');
+ $this->areaListMock->expects($this->never())->method('getCodes');
+
+ $this->processorMock->expects($this->once())
+ ->method('execute');
+
+ $this->assertSame(Cli::RETURN_SUCCESS, $this->commandTester->execute([]));
+ }
+
+ /**
+ * @return void
+ */
+ public function testExecuteWithMissingAdminhtmlLocale()
+ {
+ $this->deploymentConfigMock->expects($this->once())->method('isAvailable')->willReturn(true);
+ $this->adminhtmlAreaProcessorMock->expects($this->never())->method('process');
+ $this->areaListMock->expects($this->once())->method('getCodes')->willReturn([]);
+
+ $this->processorMock->expects($this->once())
+ ->method('execute');
+
+ $this->assertSame(Cli::RETURN_SUCCESS, $this->commandTester->execute([]));
+ }
}
diff --git a/app/code/Magento/Deploy/etc/di.xml b/app/code/Magento/Deploy/etc/di.xml
index 0c32baebf12df..d40ed3144e7e6 100644
--- a/app/code/Magento/Deploy/etc/di.xml
+++ b/app/code/Magento/Deploy/etc/di.xml
@@ -35,6 +35,12 @@
+
+
+ Magento\Config\Console\Command\EmulatedAdminhtmlAreaProcessor\Proxy
+ Magento\Framework\App\AreaList\Proxy
+
+
Magento\Framework\App\Shell
diff --git a/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php b/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php
index 9e473ccaa2d92..8bd827958df15 100644
--- a/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php
+++ b/app/code/Magento/Developer/Console/Command/XmlCatalogGenerateCommand.php
@@ -116,7 +116,7 @@ private function getUrnDictionary(OutputInterface $output)
$files = $this->filesUtility->getXmlCatalogFiles('*.xml');
$files = array_merge($files, $this->filesUtility->getXmlCatalogFiles('*.xsd'));
- $urns = [[]];
+ $urns = [];
foreach ($files as $file) {
// phpcs:ignore Magento2.Functions.DiscouragedFunction
$fileDir = dirname($file[0]);
@@ -130,7 +130,7 @@ private function getUrnDictionary(OutputInterface $output)
$urns[] = $matches[1];
}
}
- $urns = array_unique(array_merge(...$urns));
+ $urns = array_unique(array_merge([], ...$urns));
$paths = [];
foreach ($urns as $urn) {
try {
diff --git a/app/code/Magento/Dhl/Model/Carrier.php b/app/code/Magento/Dhl/Model/Carrier.php
index 204094571ba3b..c5eb27b21e58b 100644
--- a/app/code/Magento/Dhl/Model/Carrier.php
+++ b/app/code/Magento/Dhl/Model/Carrier.php
@@ -826,10 +826,9 @@ protected function _getAllItems()
$fullItems[] = array_fill(0, $qty, $this->_getWeight($itemWeight));
}
}
- if ($fullItems) {
- $fullItems = array_merge(...$fullItems);
- sort($fullItems);
- }
+
+ $fullItems = array_merge([], ...$fullItems);
+ sort($fullItems);
return $fullItems;
}
diff --git a/app/code/Magento/Directory/Model/AllowedCountries.php b/app/code/Magento/Directory/Model/AllowedCountries.php
index 2ceeb70ba5b01..69326439edc03 100644
--- a/app/code/Magento/Directory/Model/AllowedCountries.php
+++ b/app/code/Magento/Directory/Model/AllowedCountries.php
@@ -62,11 +62,11 @@ public function getAllowedCountries(
switch ($scope) {
case ScopeInterface::SCOPE_WEBSITES:
case ScopeInterface::SCOPE_STORES:
- $allowedCountries = [[]];
+ $allowedCountries = [];
foreach ($scopeCode as $singleFilter) {
$allowedCountries[] = $this->getCountriesFromConfig($this->getSingleScope($scope), $singleFilter);
}
- $allowedCountries = array_merge(...$allowedCountries);
+ $allowedCountries = array_merge([], ...$allowedCountries);
break;
default:
$allowedCountries = $this->getCountriesFromConfig($scope, $scopeCode);
diff --git a/app/code/Magento/Directory/Model/CurrencyConfig.php b/app/code/Magento/Directory/Model/CurrencyConfig.php
index f7230df6e86ea..b574170ac5d3c 100644
--- a/app/code/Magento/Directory/Model/CurrencyConfig.php
+++ b/app/code/Magento/Directory/Model/CurrencyConfig.php
@@ -73,7 +73,7 @@ public function getConfigCurrencies(string $path)
*/
private function getConfigForAllStores(string $path)
{
- $storesResult = [[]];
+ $storesResult = [];
foreach ($this->storeManager->getStores() as $store) {
$storesResult[] = explode(
',',
@@ -81,7 +81,7 @@ private function getConfigForAllStores(string $path)
);
}
- return array_merge(...$storesResult);
+ return array_merge([], ...$storesResult);
}
/**
diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForUruguay.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForUruguay.php
new file mode 100644
index 0000000000000..d9aa041c1f7d1
--- /dev/null
+++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForUruguay.php
@@ -0,0 +1,104 @@
+moduleDataSetup = $moduleDataSetup;
+ $this->dataInstallerFactory = $dataInstallerFactory;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function apply()
+ {
+ /** @var DataInstaller $dataInstaller */
+ $dataInstaller = $this->dataInstallerFactory->create();
+ $dataInstaller->addCountryRegions(
+ $this->moduleDataSetup->getConnection(),
+ $this->getDataForUruguay()
+ );
+
+ return $this;
+ }
+
+ /**
+ * Uruguay states data.
+ *
+ * @return array
+ */
+ private function getDataForUruguay(): array
+ {
+ return [
+ ['UY', 'UY-AR', 'Artigas'],
+ ['UY', 'UY-CA', 'Canelones'],
+ ['UY', 'UY-CL', 'Cerro Largo'],
+ ['UY', 'UY-CO', 'Colonia'],
+ ['UY', 'UY-DU', 'Durazno'],
+ ['UY', 'UY-FS', 'Flores'],
+ ['UY', 'UY-FD', 'Florida'],
+ ['UY', 'UY-LA', 'Lavalleja'],
+ ['UY', 'UY-MA', 'Maldonado'],
+ ['UY', 'UY-MO', 'Montevideo'],
+ ['UY', 'UY-PA', 'Paysandu'],
+ ['UY', 'UY-RN', 'Río Negro'],
+ ['UY', 'UY-RV', 'Rivera'],
+ ['UY', 'UY-RO', 'Rocha'],
+ ['UY', 'UY-SA', 'Salto'],
+ ['UY', 'UY-SJ', 'San José'],
+ ['UY', 'UY-SO', 'Soriano'],
+ ['UY', 'UY-TA', 'Tacuarembó'],
+ ['UY', 'UY-TT', 'Treinta y Tres']
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public static function getDependencies()
+ {
+ return [
+ InitializeDirectoryData::class,
+ ];
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function getAliases()
+ {
+ return [];
+ }
+}
diff --git a/app/code/Magento/Eav/Block/Adminhtml/Attribute/Edit/Options/Options.php b/app/code/Magento/Eav/Block/Adminhtml/Attribute/Edit/Options/Options.php
index 69f417e1ea732..f53f1e97a872d 100644
--- a/app/code/Magento/Eav/Block/Adminhtml/Attribute/Edit/Options/Options.php
+++ b/app/code/Magento/Eav/Block/Adminhtml/Attribute/Edit/Options/Options.php
@@ -152,7 +152,7 @@ protected function _prepareOptionValues(
$inputType = '';
}
- $values = [[]];
+ $values = [];
$isSystemAttribute = is_array($optionCollection);
if ($isSystemAttribute) {
$values[] = $this->getPreparedValues($optionCollection, $isSystemAttribute, $inputType, $defaultValues);
@@ -168,7 +168,7 @@ protected function _prepareOptionValues(
}
}
- return array_merge(...$values);
+ return array_merge([], ...$values);
}
/**
diff --git a/app/code/Magento/Eav/Model/Form.php b/app/code/Magento/Eav/Model/Form.php
index 074c6cf46a2f4..b06c084cf6675 100644
--- a/app/code/Magento/Eav/Model/Form.php
+++ b/app/code/Magento/Eav/Model/Form.php
@@ -487,11 +487,11 @@ public function validateData(array $data)
{
$validator = $this->_getValidator($data);
if (!$validator->isValid($this->getEntity())) {
- $messages = [[]];
+ $messages = [];
foreach ($validator->getMessages() as $errorMessages) {
$messages[] = (array)$errorMessages;
}
- return array_merge(...$messages);
+ return array_merge([], ...$messages);
}
return true;
}
diff --git a/app/code/Magento/Eav/Model/ResourceModel/Helper.php b/app/code/Magento/Eav/Model/ResourceModel/Helper.php
index fc8a47994a6aa..c81db40c608a8 100644
--- a/app/code/Magento/Eav/Model/ResourceModel/Helper.php
+++ b/app/code/Magento/Eav/Model/ResourceModel/Helper.php
@@ -19,6 +19,7 @@ class Helper extends \Magento\Framework\DB\Helper
* @param \Magento\Framework\App\ResourceConnection $resource
* @param string $modulePrefix
* @codeCoverageIgnore
+ * phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod
*/
public function __construct(\Magento\Framework\App\ResourceConnection $resource, $modulePrefix = 'Magento_Eav')
{
@@ -117,7 +118,7 @@ public function getLoadAttributesSelectGroups($selects)
if (array_key_exists('all', $mainGroup)) {
// it is better to call array_merge once after loop instead of calling it on each loop
- $mainGroup['all'] = array_merge(...$mainGroup['all']);
+ $mainGroup['all'] = array_merge([], ...$mainGroup['all']);
}
return array_values($mainGroup);
diff --git a/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/Product/CompositeFieldProvider.php b/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/Product/CompositeFieldProvider.php
index b276b67ff7fba..980842d6233b1 100644
--- a/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/Product/CompositeFieldProvider.php
+++ b/app/code/Magento/Elasticsearch/Model/Adapter/FieldMapper/Product/CompositeFieldProvider.php
@@ -40,12 +40,12 @@ public function __construct(array $providers)
*/
public function getFields(array $context = []): array
{
- $allAttributes = [[]];
+ $allAttributes = [];
foreach ($this->providers as $provider) {
$allAttributes[] = $provider->getFields($context);
}
- return array_merge(...$allAttributes);
+ return array_merge([], ...$allAttributes);
}
}
diff --git a/app/code/Magento/GroupedProduct/Block/Cart/Item/Renderer/Grouped.php b/app/code/Magento/GroupedProduct/Block/Cart/Item/Renderer/Grouped.php
index 197be38fb7f5f..8dc153f28c162 100644
--- a/app/code/Magento/GroupedProduct/Block/Cart/Item/Renderer/Grouped.php
+++ b/app/code/Magento/GroupedProduct/Block/Cart/Item/Renderer/Grouped.php
@@ -49,6 +49,6 @@ public function getIdentities()
if ($this->getItem()) {
$identities[] = $this->getGroupedProduct()->getIdentities();
}
- return array_merge(...$identities);
+ return array_merge([], ...$identities);
}
}
diff --git a/app/code/Magento/GroupedProduct/Block/Stockqty/Type/Grouped.php b/app/code/Magento/GroupedProduct/Block/Stockqty/Type/Grouped.php
index 97dc90ec93493..78ae4047c0aad 100644
--- a/app/code/Magento/GroupedProduct/Block/Stockqty/Type/Grouped.php
+++ b/app/code/Magento/GroupedProduct/Block/Stockqty/Type/Grouped.php
@@ -32,10 +32,10 @@ protected function _getChildProducts()
*/
public function getIdentities()
{
- $identities = [[]];
+ $identities = [];
foreach ($this->getChildProducts() as $item) {
$identities[] = $item->getIdentities();
}
- return array_merge(...$identities);
+ return array_merge([], ...$identities);
}
}
diff --git a/app/code/Magento/GroupedProduct/Model/Inventory/ParentItemProcessor.php b/app/code/Magento/GroupedProduct/Model/Inventory/ParentItemProcessor.php
new file mode 100644
index 0000000000000..0bb102f34dd2d
--- /dev/null
+++ b/app/code/Magento/GroupedProduct/Model/Inventory/ParentItemProcessor.php
@@ -0,0 +1,173 @@
+groupedType = $groupedType;
+ $this->criteriaInterfaceFactory = $criteriaInterfaceFactory;
+ $this->stockConfiguration = $stockConfiguration;
+ $this->stockItemRepository = $stockItemRepository;
+ $this->resource = $resource;
+ $this->metadataPool = $metadataPool;
+ }
+
+ /**
+ * Process parent products
+ *
+ * @param Product $product
+ * @return void
+ */
+ public function process(Product $product)
+ {
+ $parentIds = $this->getParentEntityIdsByChild($product->getId());
+ foreach ($parentIds as $productId) {
+ $this->processStockForParent((int)$productId);
+ }
+ }
+
+ /**
+ * Change stock item for parent product depending on children stock items
+ *
+ * @param int $productId
+ * @return void
+ */
+ private function processStockForParent(int $productId)
+ {
+ $criteria = $this->criteriaInterfaceFactory->create();
+ $criteria->setScopeFilter($this->stockConfiguration->getDefaultScopeId());
+ $criteria->setProductsFilter($productId);
+ $stockItemCollection = $this->stockItemRepository->getList($criteria);
+ $allItems = $stockItemCollection->getItems();
+ if (empty($allItems)) {
+ return;
+ }
+ $parentStockItem = array_shift($allItems);
+ $groupedChildrenIds = $this->groupedType->getChildrenIds($productId);
+ $criteria->setProductsFilter($groupedChildrenIds);
+ $stockItemCollection = $this->stockItemRepository->getList($criteria);
+ $allItems = $stockItemCollection->getItems();
+
+ $groupedChildrenIsInStock = false;
+
+ foreach ($allItems as $childItem) {
+ if ($childItem->getIsInStock() === true) {
+ $groupedChildrenIsInStock = true;
+ break;
+ }
+ }
+
+ if ($this->isNeedToUpdateParent($parentStockItem, $groupedChildrenIsInStock)) {
+ $parentStockItem->setIsInStock($groupedChildrenIsInStock);
+ $parentStockItem->setStockStatusChangedAuto(1);
+ $this->stockItemRepository->save($parentStockItem);
+ }
+ }
+
+ /**
+ * Check is parent item should be updated
+ *
+ * @param StockItemInterface $parentStockItem
+ * @param bool $childrenIsInStock
+ * @return bool
+ */
+ private function isNeedToUpdateParent(StockItemInterface $parentStockItem, bool $childrenIsInStock): bool
+ {
+ return $parentStockItem->getIsInStock() !== $childrenIsInStock &&
+ ($childrenIsInStock === false || $parentStockItem->getStockStatusChangedAuto());
+ }
+
+ /**
+ * Retrieve parent ids array by child id
+ *
+ * @param int $childId
+ * @return string[]
+ */
+ private function getParentEntityIdsByChild($childId)
+ {
+ $select = $this->resource->getConnection()
+ ->select()
+ ->from(['l' => $this->resource->getTableName('catalog_product_link')], [])
+ ->join(
+ ['e' => $this->resource->getTableName('catalog_product_entity')],
+ 'e.' .
+ $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField() . ' = l.product_id',
+ ['e.entity_id']
+ )
+ ->where('l.linked_product_id = ?', $childId)
+ ->where(
+ 'link_type_id = ?',
+ Link::LINK_TYPE_GROUPED
+ );
+
+ return $this->resource->getConnection()->fetchCol($select);
+ }
+}
diff --git a/app/code/Magento/GroupedProduct/etc/di.xml b/app/code/Magento/GroupedProduct/etc/di.xml
index 43678d0ad7a82..d9534c6d3fe7d 100644
--- a/app/code/Magento/GroupedProduct/etc/di.xml
+++ b/app/code/Magento/GroupedProduct/etc/di.xml
@@ -105,4 +105,11 @@
+
+
+
+ - Magento\GroupedProduct\Model\Inventory\ParentItemProcessor
+
+
+
diff --git a/app/code/Magento/GroupedProduct/view/adminhtml/ui_component/grouped_product_listing.xml b/app/code/Magento/GroupedProduct/view/adminhtml/ui_component/grouped_product_listing.xml
index 831dc5a765dfb..becd7ca8079da 100644
--- a/app/code/Magento/GroupedProduct/view/adminhtml/ui_component/grouped_product_listing.xml
+++ b/app/code/Magento/GroupedProduct/view/adminhtml/ui_component/grouped_product_listing.xml
@@ -58,7 +58,7 @@
status
- componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php
index 55992c92226af..87cd4cf346288 100644
--- a/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php
+++ b/app/code/Magento/ImportExport/Block/Adminhtml/Import/Edit/Form.php
@@ -226,6 +226,7 @@ protected function _prepareForm()
'title' => __('Select File to Import'),
'required' => true,
'class' => 'input-file',
+ 'onchange' => 'varienImport.refreshLoadedFileLastModified(this);',
'note' => __(
'File must be saved in UTF-8 encoding for proper import'
),
@@ -282,7 +283,7 @@ protected function getDownloadSampleFileHtml()
private function getImportBehaviorTooltip()
{
$html = '
';
diff --git a/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php
index 5ea6227231543..2f8bfdcf70a5e 100644
--- a/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php
+++ b/app/code/Magento/ImportExport/Model/Import/ErrorProcessing/ProcessingErrorAggregator.php
@@ -242,7 +242,7 @@ public function getAllErrors()
}
$errors = array_values($this->items['rows']);
- return array_merge(...$errors);
+ return array_merge([], ...$errors);
}
/**
@@ -253,14 +253,14 @@ public function getAllErrors()
*/
public function getErrorsByCode(array $codes)
{
- $result = [[]];
+ $result = [];
foreach ($codes as $code) {
if (isset($this->items['codes'][$code])) {
$result[] = $this->items['codes'][$code];
}
}
- return array_merge(...$result);
+ return array_merge([], ...$result);
}
/**
diff --git a/app/code/Magento/ImportExport/i18n/en_US.csv b/app/code/Magento/ImportExport/i18n/en_US.csv
index a4943fe72826f..a91a76612fd9f 100644
--- a/app/code/Magento/ImportExport/i18n/en_US.csv
+++ b/app/code/Magento/ImportExport/i18n/en_US.csv
@@ -127,3 +127,4 @@ Summary,Summary
"File %1 deleted","File %1 deleted"
"Please provide valid export file name","Please provide valid export file name"
"%1 is not a valid file","%1 is not a valid file"
+"Content of uploaded file was changed, please re-upload the file","Content of uploaded file was changed, please re-upload the file"
diff --git a/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml b/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml
index 69779baba381d..d512ce8182ede 100644
--- a/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml
+++ b/app/code/Magento/ImportExport/view/adminhtml/templates/import/form/before.phtml
@@ -7,6 +7,10 @@
escapeHtml(
+ __('Content of uploaded file was changed, please re-upload the file')
+);
?>
escapeJs($block->getUrl('*/*/download/', ['filename' => 'entity-name']))}',
+ /**
+ * Loaded file last modified
+ * @type {int|null}
+ */
+ loadedFileLastModified: null,
+
/**
* Reset selected index
* @param {string} elementId
@@ -162,11 +172,50 @@ require([
}
},
+ /**
+ * Refresh loaded file last modified
+ */
+ refreshLoadedFileLastModified: function(e) {
+ if (jQuery(e)[0].files.length > 0) {
+ this.loadedFileLastModified = jQuery(e)[0].files[0].lastModified;
+ } else {
+ this.loadedFileLastModified = null;
+ }
+ },
+
/**
* Post form data to dynamic iframe.
* @param {string} newActionUrl OPTIONAL Change form action to this if specified
*/
postToFrame: function(newActionUrl) {
+ var fileUploader = document.getElementById('{$fieldNameSourceFile}');
+
+ if (fileUploader.files.length > 0) {
+ var file = fileUploader.files[0],
+ ifrElName = this.ifrElemName,
+ reader = new FileReader();
+
+ reader.readAsText(file, "UTF-8");
+
+ reader.onerror = function () {
+ jQuery('body').loader('hide');
+ alert({
+ content: '{$uploaderErrorMessage}'
+ });
+ fileUploader.value = null;
+ jQuery('iframe#' + ifrElName).remove();
+ return;
+ }
+
+ if (file.lastModified !== this.loadedFileLastModified) {
+ alert({
+ content: '{$uploaderErrorMessage}'
+ });
+ fileUploader.value = null;
+ return;
+ }
+ }
+
if (!jQuery('[name="' + this.ifrElemName + '"]').length) {
jQuery('body').append('
');
jQuery('iframe#' + this.ifrElemName).attr('display', 'none');
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
index e7517ba0c8818..735bc85244bdb 100644
--- a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
+++ b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
@@ -125,16 +125,16 @@ protected function getIndexers(InputInterface $input)
return $indexers;
}
- $relatedIndexers = [[]];
- $dependentIndexers = [[]];
+ $relatedIndexers = [];
+ $dependentIndexers = [];
foreach ($indexers as $indexer) {
$relatedIndexers[] = $this->getRelatedIndexerIds($indexer->getId());
$dependentIndexers[] = $this->getDependentIndexerIds($indexer->getId());
}
- $relatedIndexers = $relatedIndexers ? array_unique(array_merge(...$relatedIndexers)) : [];
- $dependentIndexers = $dependentIndexers ? array_merge(...$dependentIndexers) : [];
+ $relatedIndexers = array_unique(array_merge([], ...$relatedIndexers));
+ $dependentIndexers = array_merge([], ...$dependentIndexers);
$invalidRelatedIndexers = [];
foreach ($relatedIndexers as $relatedIndexer) {
@@ -165,12 +165,12 @@ protected function getIndexers(InputInterface $input)
*/
private function getRelatedIndexerIds(string $indexerId): array
{
- $relatedIndexerIds = [[]];
+ $relatedIndexerIds = [];
foreach ($this->getDependencyInfoProvider()->getIndexerIdsToRunBefore($indexerId) as $relatedIndexerId) {
$relatedIndexerIds[] = [$relatedIndexerId];
$relatedIndexerIds[] = $this->getRelatedIndexerIds($relatedIndexerId);
}
- $relatedIndexerIds = $relatedIndexerIds ? array_unique(array_merge(...$relatedIndexerIds)) : [];
+ $relatedIndexerIds = array_unique(array_merge([], ...$relatedIndexerIds));
return $relatedIndexerIds;
}
@@ -183,7 +183,7 @@ private function getRelatedIndexerIds(string $indexerId): array
*/
private function getDependentIndexerIds(string $indexerId): array
{
- $dependentIndexerIds = [[]];
+ $dependentIndexerIds = [];
foreach (array_keys($this->getConfig()->getIndexers()) as $id) {
$dependencies = $this->getDependencyInfoProvider()->getIndexerIdsToRunBefore($id);
if (array_search($indexerId, $dependencies) !== false) {
@@ -191,7 +191,7 @@ private function getDependentIndexerIds(string $indexerId): array
$dependentIndexerIds[] = $this->getDependentIndexerIds($id);
}
}
- $dependentIndexerIds = $dependentIndexerIds ? array_unique(array_merge(...$dependentIndexerIds)) : [];
+ $dependentIndexerIds = array_unique(array_merge([], ...$dependentIndexerIds));
return $dependentIndexerIds;
}
diff --git a/app/code/Magento/Integration/Block/Adminhtml/Integration/Activate/Permissions/Tab/Webapi.php b/app/code/Magento/Integration/Block/Adminhtml/Integration/Activate/Permissions/Tab/Webapi.php
index 2d323fea34e7d..b6ea810666b9b 100644
--- a/app/code/Magento/Integration/Block/Adminhtml/Integration/Activate/Permissions/Tab/Webapi.php
+++ b/app/code/Magento/Integration/Block/Adminhtml/Integration/Activate/Permissions/Tab/Webapi.php
@@ -222,13 +222,13 @@ public function isTreeEmpty()
*/
protected function _getAllResourceIds(array $resources)
{
- $resourceIds = [[]];
+ $resourceIds = [];
foreach ($resources as $resource) {
$resourceIds[] = [$resource['id']];
if (isset($resource['children'])) {
$resourceIds[] = $this->_getAllResourceIds($resource['children']);
}
}
- return array_merge(...$resourceIds);
+ return array_merge([], ...$resourceIds);
}
}
diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/ActionGroup/StorefrontAssertAppliedFilterActionGroup.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/ActionGroup/StorefrontAssertAppliedFilterActionGroup.xml
new file mode 100644
index 0000000000000..92fea20a83157
--- /dev/null
+++ b/app/code/Magento/LayeredNavigation/Test/Mftf/ActionGroup/StorefrontAssertAppliedFilterActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Asserts applied filter label and value on storefront category page.
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/ActionGroup/StorefrontFilterCategoryPageByAttributeOptionActionGroup.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/ActionGroup/StorefrontFilterCategoryPageByAttributeOptionActionGroup.xml
new file mode 100644
index 0000000000000..f6fe2b20185e6
--- /dev/null
+++ b/app/code/Magento/LayeredNavigation/Test/Mftf/ActionGroup/StorefrontFilterCategoryPageByAttributeOptionActionGroup.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ Filters storefront category page by given filterable attribute and attribute option.
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/Section/LayeredNavigationSection/StorefrontLayeredNavigationSection.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/Section/LayeredNavigationSection/StorefrontLayeredNavigationSection.xml
index d3a3005c296b2..d8a103116ef06 100644
--- a/app/code/Magento/LayeredNavigation/Test/Mftf/Section/LayeredNavigationSection/StorefrontLayeredNavigationSection.xml
+++ b/app/code/Magento/LayeredNavigation/Test/Mftf/Section/LayeredNavigationSection/StorefrontLayeredNavigationSection.xml
@@ -9,5 +9,7 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontDropdownAttributeInLayeredNavigationTest.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontDropdownAttributeInLayeredNavigationTest.xml
new file mode 100644
index 0000000000000..0cd115d3febeb
--- /dev/null
+++ b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontDropdownAttributeInLayeredNavigationTest.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/LayeredNavigation/view/frontend/templates/layer/filter.phtml b/app/code/Magento/LayeredNavigation/view/frontend/templates/layer/filter.phtml
index 6b65d184b462a..83f40ab4911e7 100644
--- a/app/code/Magento/LayeredNavigation/view/frontend/templates/layer/filter.phtml
+++ b/app/code/Magento/LayeredNavigation/view/frontend/templates/layer/filter.phtml
@@ -4,10 +4,10 @@
* See COPYING.txt for license details.
*/
-// phpcs:disable Magento2.Templates.ThisInTemplate.FoundThis
?>
getData('product_layer_view_model');
?>
@@ -16,28 +16,29 @@ $viewModel = $block->getData('product_layer_view_model');
getCount() > 0): ?>
-
- = /* @noEscape */ $filterItem->getLabel() ?>
- shouldDisplayProductCountOnLayer()): ?>
- = /* @noEscape */ (int)$filterItem->getCount() ?>
-
- getCount() == 1):
- ?> = $block->escapeHtml(__('item')) ?>escapeUrl($filterItem->getUrl()) ?>"
+ rel="nofollow"
+ >= /* @noEscape */ $filterItem->getLabel() ?>shouldDisplayProductCountOnLayer()): ?>= /* @noEscape */ (int) $filterItem->getCount() ?>getCount() == 1): ?>
+ = $escaper->escapeHtml(__('item')) ?> = $block->escapeHtml(__('item')) ?>= $escaper->escapeHtml(__('item')) ?>
-
-
+
- = /* @noEscape */ $filterItem->getLabel() ?>
- shouldDisplayProductCountOnLayer()): ?>
- = /* @noEscape */ (int)$filterItem->getCount() ?>
-
- getCount() == 1):
- ?>= $block->escapeHtml(__('items')) ?>= $block->escapeHtml(__('items')) ?>
+ = /* @noEscape */ $filterItem->getLabel() ?>shouldDisplayProductCountOnLayer()): ?>= /* @noEscape */ (int) $filterItem->getCount() ?>getCount() == 1): ?>
+ = $escaper->escapeHtml(__('items')) ?>= $escaper->escapeHtml(__('items')) ?>
diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUIShownIfLoginAsCustomerEnabledTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUIShownIfLoginAsCustomerEnabledTest.xml
index ea06263901b9e..26ffc877bbe42 100644
--- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUIShownIfLoginAsCustomerEnabledTest.xml
+++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUIShownIfLoginAsCustomerEnabledTest.xml
@@ -23,13 +23,18 @@
stepKey="enableLoginAsCustomer"/>
-
+
+
+
+
+
+
@@ -39,7 +44,12 @@
-
+
+
+
+
+
+
diff --git a/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php b/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php
index fd61f96b300d6..472d1cc631290 100644
--- a/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php
+++ b/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php
@@ -131,7 +131,7 @@ public function run()
];
if ($maxMessages) {
- $arguments[] = '--max-messages=' . $maxMessages;
+ $arguments[] = '--max-messages=' . min($consumer->getMaxMessages() ?? $maxMessages, $maxMessages);
}
$command = $php . ' ' . BP . '/bin/magento queue:consumers:start %s %s'
diff --git a/app/code/Magento/Multishipping/Block/Checkout/Overview.php b/app/code/Magento/Multishipping/Block/Checkout/Overview.php
index 1ea2dc2618778..942741e9f7975 100644
--- a/app/code/Magento/Multishipping/Block/Checkout/Overview.php
+++ b/app/code/Magento/Multishipping/Block/Checkout/Overview.php
@@ -10,6 +10,8 @@
use Magento\Quote\Model\Quote\Address;
use Magento\Checkout\Helper\Data as CheckoutHelper;
use Magento\Framework\App\ObjectManager;
+use Magento\Quote\Model\Quote\Address\Total\Collector;
+use Magento\Store\Model\ScopeInterface;
/**
* Multishipping checkout overview information
@@ -429,9 +431,12 @@ public function getBillingAddressTotals()
*/
public function renderTotals($totals, $colspan = null)
{
- //check if the shipment is multi shipment
+ // check if the shipment is multi shipment
$totals = $this->getMultishippingTotals($totals);
+ // sort totals by configuration settings
+ $totals = $this->sortTotals($totals);
+
if ($colspan === null) {
$colspan = 3;
}
@@ -481,4 +486,38 @@ protected function _getRowItemRenderer($type)
}
return $renderer;
}
+
+ /**
+ * Sort total information based on configuration settings.
+ *
+ * @param array $totals
+ * @return array
+ */
+ private function sortTotals($totals): array
+ {
+ $sortedTotals = [];
+ $sorts = $this->_scopeConfig->getValue(
+ Collector::XML_PATH_SALES_TOTALS_SORT,
+ ScopeInterface::SCOPE_STORES
+ );
+
+ $sorted = [];
+ foreach ($sorts as $code => $sortOrder) {
+ $sorted[$sortOrder] = $code;
+ }
+ ksort($sorted);
+
+ foreach ($sorted as $code) {
+ if (isset($totals[$code])) {
+ $sortedTotals[$code] = $totals[$code];
+ }
+ }
+
+ $notSorted = array_diff(array_keys($totals), array_keys($sortedTotals));
+ foreach ($notSorted as $code) {
+ $sortedTotals[$code] = $totals[$code];
+ }
+
+ return $sortedTotals;
+ }
}
diff --git a/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php b/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php
index 7da77030f308a..2d044afd32c70 100644
--- a/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php
+++ b/app/code/Magento/Multishipping/Test/Unit/Block/Checkout/OverviewTest.php
@@ -8,6 +8,7 @@
namespace Magento\Multishipping\Test\Unit\Block\Checkout;
+use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Framework\UrlInterface;
@@ -67,6 +68,11 @@ class OverviewTest extends TestCase
*/
private $urlBuilderMock;
+ /**
+ * @var MockObject
+ */
+ private $scopeConfigMock;
+
protected function setUp(): void
{
$objectManager = new ObjectManager($this);
@@ -85,6 +91,7 @@ protected function setUp(): void
$this->createMock(Multishipping::class);
$this->quoteMock = $this->createMock(Quote::class);
$this->urlBuilderMock = $this->getMockForAbstractClass(UrlInterface::class);
+ $this->scopeConfigMock = $this->getMockForAbstractClass(ScopeConfigInterface::class);
$this->model = $objectManager->getObject(
Overview::class,
[
@@ -92,7 +99,8 @@ protected function setUp(): void
'totalsCollector' => $this->totalsCollectorMock,
'totalsReader' => $this->totalsReaderMock,
'multishipping' => $this->checkoutMock,
- 'urlBuilder' => $this->urlBuilderMock
+ 'urlBuilder' => $this->urlBuilderMock,
+ '_scopeConfig' => $this->scopeConfigMock
]
);
}
@@ -187,4 +195,44 @@ public function testGetVirtualProductEditUrl()
$this->urlBuilderMock->expects($this->once())->method('getUrl')->with('checkout/cart', [])->willReturn($url);
$this->assertEquals($url, $this->model->getVirtualProductEditUrl());
}
+
+ /**
+ * Test sort total information
+ *
+ * @return void
+ */
+ public function testSortCollectors(): void
+ {
+ $sorts = [
+ 'discount' => 40,
+ 'subtotal' => 10,
+ 'tax' => 20,
+ 'shipping' => 30,
+ ];
+
+ $this->scopeConfigMock->method('getValue')
+ ->with('sales/totals_sort', 'stores')
+ ->willReturn($sorts);
+
+ $totalsNotSorted = [
+ 'subtotal' => [],
+ 'shipping' => [],
+ 'tax' => [],
+ ];
+
+ $totalsExpected = [
+ 'subtotal' => [],
+ 'tax' => [],
+ 'shipping' => [],
+ ];
+
+ $method = new \ReflectionMethod($this->model, 'sortTotals');
+ $method->setAccessible(true);
+ $result = $method->invoke($this->model, $totalsNotSorted);
+
+ $this->assertEquals(
+ $totalsExpected,
+ $result
+ );
+ }
}
diff --git a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php
index bbc199c91263a..112accbae8070 100644
--- a/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php
+++ b/app/code/Magento/OfflineShipping/Model/Carrier/Tablerate.php
@@ -140,10 +140,9 @@ public function collectRates(RateRequest $request)
$freePackageValue += $item->getBaseRowTotal();
}
}
- $oldValue = $request->getPackageValue();
- $newPackageValue = $oldValue - $freePackageValue;
- $request->setPackageValue($newPackageValue);
- $request->setPackageValueWithDiscount($newPackageValue);
+
+ $request->setPackageValue($request->getPackageValue() - $freePackageValue);
+ $request->setPackageValueWithDiscount($request->getPackageValueWithDiscount() - $freePackageValue);
}
if (!$request->getConditionName()) {
diff --git a/app/code/Magento/OfflineShipping/Test/Mftf/Test/SalesRuleDiscountIsAppliedOnPackageValueForTableRateTest.xml b/app/code/Magento/OfflineShipping/Test/Mftf/Test/SalesRuleDiscountIsAppliedOnPackageValueForTableRateTest.xml
new file mode 100644
index 0000000000000..d225e5fa28f97
--- /dev/null
+++ b/app/code/Magento/OfflineShipping/Test/Mftf/Test/SalesRuleDiscountIsAppliedOnPackageValueForTableRateTest.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 13.00
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/PageCache/Model/Layout/LayoutPlugin.php b/app/code/Magento/PageCache/Model/Layout/LayoutPlugin.php
index 1b64f3b635c03..6aff8aef2c2d9 100644
--- a/app/code/Magento/PageCache/Model/Layout/LayoutPlugin.php
+++ b/app/code/Magento/PageCache/Model/Layout/LayoutPlugin.php
@@ -84,7 +84,7 @@ public function afterGenerateElements(Layout $subject)
public function afterGetOutput(Layout $subject, $result)
{
if ($subject->isCacheable() && $this->config->isEnabled()) {
- $tags = [[]];
+ $tags = [];
$isVarnish = $this->config->getType() === Config::VARNISH;
foreach ($subject->getAllBlocks() as $block) {
@@ -96,7 +96,7 @@ public function afterGetOutput(Layout $subject, $result)
$tags[] = $block->getIdentities();
}
}
- $tags = array_unique(array_merge(...$tags));
+ $tags = array_unique(array_merge([], ...$tags));
$tags = $this->pageCacheTagsPreprocessor->process($tags);
$this->response->setHeader('X-Magento-Tags', implode(',', $tags));
}
diff --git a/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php b/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php
index 8c8d13300849e..af42554484117 100644
--- a/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php
+++ b/app/code/Magento/Payment/Gateway/Validator/ValidatorComposite.php
@@ -59,8 +59,8 @@ public function __construct(
public function validate(array $validationSubject)
{
$isValid = true;
- $failsDescriptionAggregate = [[]];
- $errorCodesAggregate = [[]];
+ $failsDescriptionAggregate = [];
+ $errorCodesAggregate = [];
foreach ($this->validators as $key => $validator) {
$result = $validator->validate($validationSubject);
if (!$result->isValid()) {
@@ -76,8 +76,8 @@ public function validate(array $validationSubject)
return $this->createResult(
$isValid,
- array_merge(...$failsDescriptionAggregate),
- array_merge(...$errorCodesAggregate)
+ array_merge([], ...$failsDescriptionAggregate),
+ array_merge([], ...$errorCodesAggregate)
);
}
}
diff --git a/app/code/Magento/Payment/Model/PaymentMethodList.php b/app/code/Magento/Payment/Model/PaymentMethodList.php
index 4e400dbf0c906..b27d02bbdff4b 100644
--- a/app/code/Magento/Payment/Model/PaymentMethodList.php
+++ b/app/code/Magento/Payment/Model/PaymentMethodList.php
@@ -6,53 +6,57 @@
namespace Magento\Payment\Model;
use Magento\Payment\Api\Data\PaymentMethodInterface;
+use Magento\Payment\Api\Data\PaymentMethodInterfaceFactory;
+use Magento\Payment\Api\PaymentMethodListInterface;
+use Magento\Payment\Helper\Data;
+use UnexpectedValueException;
-/**
- * Payment method list class.
- */
-class PaymentMethodList implements \Magento\Payment\Api\PaymentMethodListInterface
+class PaymentMethodList implements PaymentMethodListInterface
{
/**
- * @var \Magento\Payment\Api\Data\PaymentMethodInterfaceFactory
+ * @var PaymentMethodInterfaceFactory
*/
private $methodFactory;
/**
- * @var \Magento\Payment\Helper\Data
+ * @var Data
*/
private $helper;
/**
- * @param \Magento\Payment\Api\Data\PaymentMethodInterfaceFactory $methodFactory
- * @param \Magento\Payment\Helper\Data $helper
+ * @param PaymentMethodInterfaceFactory $methodFactory
+ * @param Data $helper
*/
public function __construct(
- \Magento\Payment\Api\Data\PaymentMethodInterfaceFactory $methodFactory,
- \Magento\Payment\Helper\Data $helper
+ PaymentMethodInterfaceFactory $methodFactory,
+ Data $helper
) {
$this->methodFactory = $methodFactory;
$this->helper = $helper;
}
/**
- * {@inheritdoc}
+ * @inheritDoc
*/
public function getList($storeId)
{
$methodsCodes = array_keys($this->helper->getPaymentMethods());
-
$methodsInstances = array_map(
function ($code) {
- return $this->helper->getMethodInstance($code);
+ try {
+ return $this->helper->getMethodInstance($code);
+ } catch (UnexpectedValueException $e) {
+ return null;
+ }
},
$methodsCodes
);
- $methodsInstances = array_filter($methodsInstances, function (MethodInterface $method) {
- return !($method instanceof \Magento\Payment\Model\Method\Substitution);
+ $methodsInstances = array_filter($methodsInstances, function ($method) {
+ return $method && !($method instanceof \Magento\Payment\Model\Method\Substitution);
});
- @uasort(
+ uasort(
$methodsInstances,
function (MethodInterface $a, MethodInterface $b) use ($storeId) {
return (int)$a->getConfigData('sort_order', $storeId) - (int)$b->getConfigData('sort_order', $storeId);
@@ -76,7 +80,7 @@ function (MethodInterface $methodInstance) use ($storeId) {
}
/**
- * {@inheritdoc}
+ * @inheritDoc
*/
public function getActiveList($storeId)
{
diff --git a/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php b/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php
index 29d4a5bd1f25c..95dc8ee487edf 100644
--- a/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php
+++ b/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php
@@ -174,6 +174,7 @@ protected function _processPaypalApiError($exception)
$this->_redirectSameToken();
break;
case ApiProcessableException::API_ADDRESS_MATCH_FAIL:
+ case ApiProcessableException::API_TRANSACTION_HAS_BEEN_COMPLETED:
$this->redirectToOrderReviewPageAndShowError($exception->getUserMessage());
break;
case ApiProcessableException::API_UNABLE_TRANSACTION_COMPLETE:
diff --git a/app/code/Magento/Paypal/Model/Api/Nvp.php b/app/code/Magento/Paypal/Model/Api/Nvp.php
index b35f783482e06..30bfb660aa6f1 100644
--- a/app/code/Magento/Paypal/Model/Api/Nvp.php
+++ b/app/code/Magento/Paypal/Model/Api/Nvp.php
@@ -1286,15 +1286,6 @@ protected function _handleCallErrors($response)
);
$this->_logger->critical($exceptionLogMessage);
- /**
- * The response code 10415 'Transaction has already been completed for this token'
- * must not fails place order. The old Paypal interface does not lock 'Send' button
- * it may result to re-send data.
- */
- if (in_array((string)ProcessableException::API_TRANSACTION_HAS_BEEN_COMPLETED, $this->_callErrors)) {
- return;
- }
-
$exceptionPhrase = __('PayPal gateway has rejected request. %1', $errorMessages);
/** @var \Magento\Framework\Exception\LocalizedException $exception */
diff --git a/app/code/Magento/Paypal/Model/Api/ProcessableException.php b/app/code/Magento/Paypal/Model/Api/ProcessableException.php
index 40ee6d98c4381..12a11ff442418 100644
--- a/app/code/Magento/Paypal/Model/Api/ProcessableException.php
+++ b/app/code/Magento/Paypal/Model/Api/ProcessableException.php
@@ -67,6 +67,12 @@ public function getUserMessage()
. ' Please contact us so we can assist you.'
);
break;
+ case self::API_TRANSACTION_HAS_BEEN_COMPLETED:
+ $message = __(
+ 'A successful payment transaction has already been completed.'
+ . ' Please, check if the order has been placed.'
+ );
+ break;
case self::API_ADDRESS_MATCH_FAIL:
$message = __(
'A match of the Shipping Address City, State, and Postal Code failed.'
diff --git a/app/code/Magento/Paypal/Model/Config/Structure/PaymentSectionModifier.php b/app/code/Magento/Paypal/Model/Config/Structure/PaymentSectionModifier.php
index 61410499e956e..a3cef539dc17b 100644
--- a/app/code/Magento/Paypal/Model/Config/Structure/PaymentSectionModifier.php
+++ b/app/code/Magento/Paypal/Model/Config/Structure/PaymentSectionModifier.php
@@ -84,7 +84,7 @@ public function modify(array $initialStructure)
*/
private function getMoveInstructions($section, $data)
{
- $moved = [[]];
+ $moved = [];
if (array_key_exists('children', $data)) {
foreach ($data['children'] as $childSection => $childData) {
@@ -106,6 +106,6 @@ private function getMoveInstructions($section, $data)
];
}
- return array_merge(...$moved);
+ return array_merge([], ...$moved);
}
}
diff --git a/app/code/Magento/Paypal/Model/Express.php b/app/code/Magento/Paypal/Model/Express.php
index 946c0fd4c66ca..39b1c6f7e3c28 100644
--- a/app/code/Magento/Paypal/Model/Express.php
+++ b/app/code/Magento/Paypal/Model/Express.php
@@ -276,6 +276,7 @@ protected function _setApiProcessableErrors()
ApiProcessableException::API_MAXIMUM_AMOUNT_FILTER_DECLINE,
ApiProcessableException::API_OTHER_FILTER_DECLINE,
ApiProcessableException::API_ADDRESS_MATCH_FAIL,
+ ApiProcessableException::API_TRANSACTION_HAS_BEEN_COMPLETED,
self::$authorizationExpiredCode
]
);
diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Api/NvpTest.php b/app/code/Magento/Paypal/Test/Unit/Model/Api/NvpTest.php
index 42b99ae8e7459..69aa9b99bc9e7 100644
--- a/app/code/Magento/Paypal/Test/Unit/Model/Api/NvpTest.php
+++ b/app/code/Magento/Paypal/Test/Unit/Model/Api/NvpTest.php
@@ -305,8 +305,7 @@ public function testGetDebugReplacePrivateDataKeys()
/**
* Tests case if obtained response with code 10415 'Transaction has already
- * been completed for this token'. It must does not throws the exception and
- * must returns response array.
+ * been completed for this token'. It must throw the ProcessableException.
*/
public function testCallTransactionHasBeenCompleted()
{
@@ -317,15 +316,10 @@ public function testCallTransactionHasBeenCompleted()
->method('read')
->willReturn($response);
$this->model->setProcessableErrors($processableErrors);
- $this->customLoggerMock->expects($this->once())
- ->method('debug');
- $expectedResponse = [
- 'ACK' => 'Failure',
- 'L_ERRORCODE0' => '10415',
- 'L_SHORTMESSAGE0' => 'Message.',
- 'L_LONGMESSAGE0' => 'Long Message.'
- ];
- $this->assertEquals($expectedResponse, $this->model->call('some method', ['data' => 'some data']));
+ $this->expectExceptionMessageMatches('/PayPal gateway has rejected request/');
+ $this->expectException(ProcessableException::class);
+
+ $this->model->call('DoExpressCheckout', ['data' => 'some data']);
}
}
diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Config/Structure/PaymentSectionModifierTest.php b/app/code/Magento/Paypal/Test/Unit/Model/Config/Structure/PaymentSectionModifierTest.php
index dc54b71324a9b..a6a18418e92ac 100644
--- a/app/code/Magento/Paypal/Test/Unit/Model/Config/Structure/PaymentSectionModifierTest.php
+++ b/app/code/Magento/Paypal/Test/Unit/Model/Config/Structure/PaymentSectionModifierTest.php
@@ -162,14 +162,14 @@ public function testMovedToTargetSpecialGroup()
*/
private function fetchAllAvailableGroups($structure)
{
- $availableGroups = [[]];
+ $availableGroups = [];
foreach ($structure as $group => $data) {
$availableGroups[] = [$group];
if (isset($data['children'])) {
$availableGroups[] = $this->fetchAllAvailableGroups($data['children']);
}
}
- $availableGroups = array_merge(...$availableGroups);
+ $availableGroups = array_merge([], ...$availableGroups);
$availableGroups = array_values(array_unique($availableGroups));
sort($availableGroups);
return $availableGroups;
diff --git a/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php b/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php
index 8cf2fb91a8452..14dcc4fc4229d 100644
--- a/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php
+++ b/app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php
@@ -53,6 +53,7 @@ class ExpressTest extends TestCase
ApiProcessableException::API_MAXIMUM_AMOUNT_FILTER_DECLINE,
ApiProcessableException::API_OTHER_FILTER_DECLINE,
ApiProcessableException::API_ADDRESS_MATCH_FAIL,
+ ApiProcessableException::API_TRANSACTION_HAS_BEEN_COMPLETED
];
/**
diff --git a/app/code/Magento/Paypal/i18n/en_US.csv b/app/code/Magento/Paypal/i18n/en_US.csv
index 8db6285dc157e..a8f26b422dc7c 100644
--- a/app/code/Magento/Paypal/i18n/en_US.csv
+++ b/app/code/Magento/Paypal/i18n/en_US.csv
@@ -737,3 +737,4 @@ User,User
"Please enter at least 0 and at most 65535","Please enter at least 0 and at most 65535"
"Order is suspended as an account verification transaction is suspected to be fraudulent.","Order is suspended as an account verification transaction is suspected to be fraudulent."
"Payment can't be accepted since transaction was rejected by merchant.","Payment can't be accepted since transaction was rejected by merchant."
+"A successful payment transaction has already been completed. Please, check if the order has been placed.","A successful payment transaction has already been completed. Please, check if the order has been placed."
diff --git a/app/code/Magento/Persistent/Model/QuoteManager.php b/app/code/Magento/Persistent/Model/QuoteManager.php
index b6504d528fbe4..35b07ebdb7c44 100644
--- a/app/code/Magento/Persistent/Model/QuoteManager.php
+++ b/app/code/Magento/Persistent/Model/QuoteManager.php
@@ -5,6 +5,7 @@
*/
namespace Magento\Persistent\Model;
+use Magento\Customer\Api\Data\CustomerInterfaceFactory;
use Magento\Customer\Api\Data\GroupInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Persistent\Helper\Data;
@@ -64,6 +65,11 @@ class QuoteManager
*/
private $cartExtensionFactory;
+ /**
+ * @var CustomerInterfaceFactory
+ */
+ private $customerDataFactory;
+
/**
* @param \Magento\Persistent\Helper\Session $persistentSession
* @param Data $persistentData
@@ -71,6 +77,7 @@ class QuoteManager
* @param CartRepositoryInterface $quoteRepository
* @param CartExtensionFactory|null $cartExtensionFactory
* @param ShippingAssignmentProcessor|null $shippingAssignmentProcessor
+ * @param CustomerInterfaceFactory|null $customerDataFactory
*/
public function __construct(
\Magento\Persistent\Helper\Session $persistentSession,
@@ -78,7 +85,8 @@ public function __construct(
\Magento\Checkout\Model\Session $checkoutSession,
CartRepositoryInterface $quoteRepository,
?CartExtensionFactory $cartExtensionFactory = null,
- ?ShippingAssignmentProcessor $shippingAssignmentProcessor = null
+ ?ShippingAssignmentProcessor $shippingAssignmentProcessor = null,
+ ?CustomerInterfaceFactory $customerDataFactory = null
) {
$this->persistentSession = $persistentSession;
$this->persistentData = $persistentData;
@@ -88,6 +96,8 @@ public function __construct(
?? ObjectManager::getInstance()->get(CartExtensionFactory::class);
$this->shippingAssignmentProcessor = $shippingAssignmentProcessor
?? ObjectManager::getInstance()->get(ShippingAssignmentProcessor::class);
+ $this->customerDataFactory = $customerDataFactory
+ ?? ObjectManager::getInstance()->get(CustomerInterfaceFactory::class);
}
/**
@@ -109,14 +119,11 @@ public function setGuest($checkQuote = false)
$quote->getPaymentsCollection()->walk('delete');
$quote->getAddressesCollection()->walk('delete');
$this->_setQuotePersistent = false;
+ $this->cleanCustomerData($quote);
$quote->setIsActive(true)
- ->setCustomerId(null)
- ->setCustomerEmail(null)
- ->setCustomerFirstname(null)
- ->setCustomerLastname(null)
- ->setCustomerGroupId(GroupInterface::NOT_LOGGED_IN_ID)
->setIsPersistent(false)
->removeAllAddresses();
+
//Create guest addresses
$quote->getShippingAddress();
$quote->getBillingAddress();
@@ -129,6 +136,27 @@ public function setGuest($checkQuote = false)
$this->persistentSession->setSession(null);
}
+ /**
+ * Clear customer data in quote
+ *
+ * @param Quote $quote
+ */
+ private function cleanCustomerData($quote)
+ {
+ /**
+ * Set empty customer object in quote to avoid restore customer id
+ * @see Quote::beforeSave()
+ */
+ if ($quote->getCustomerId()) {
+ $quote->setCustomer($this->customerDataFactory->create());
+ }
+ $quote->setCustomerId(null)
+ ->setCustomerEmail(null)
+ ->setCustomerFirstname(null)
+ ->setCustomerLastname(null)
+ ->setCustomerGroupId(GroupInterface::NOT_LOGGED_IN_ID);
+ }
+
/**
* Emulate guest cart with persistent cart
*
diff --git a/app/code/Magento/Persistent/Observer/MakePersistentQuoteGuestObserver.php b/app/code/Magento/Persistent/Observer/MakePersistentQuoteGuestObserver.php
index f2f9b96fa82e4..98c9c3df27852 100644
--- a/app/code/Magento/Persistent/Observer/MakePersistentQuoteGuestObserver.php
+++ b/app/code/Magento/Persistent/Observer/MakePersistentQuoteGuestObserver.php
@@ -1,16 +1,14 @@
_persistentSession = $persistentSession;
$this->_persistentData = $persistentData;
$this->_customerSession = $customerSession;
- $this->quoteManager = $quoteManager;
+ $this->checkoutSession = $checkoutSession;
}
/**
@@ -74,7 +72,7 @@ public function execute(\Magento\Framework\Event\Observer $observer)
if (($this->_persistentSession->isPersistent() && !$this->_customerSession->isLoggedIn())
|| $this->_persistentData->isShoppingCartPersist()
) {
- $this->quoteManager->setGuest(true);
+ $this->checkoutSession->clearQuote()->clearStorage();
}
}
}
diff --git a/app/code/Magento/Persistent/Observer/RemoveGuestPersistenceOnEmptyCartObserver.php b/app/code/Magento/Persistent/Observer/RemoveGuestPersistenceOnEmptyCartObserver.php
index fe754711c910b..efc9ecd4c1a59 100644
--- a/app/code/Magento/Persistent/Observer/RemoveGuestPersistenceOnEmptyCartObserver.php
+++ b/app/code/Magento/Persistent/Observer/RemoveGuestPersistenceOnEmptyCartObserver.php
@@ -10,6 +10,8 @@
/**
* Observer to remove persistent session if guest empties persistent cart previously created and added to by customer.
+ *
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class RemoveGuestPersistenceOnEmptyCartObserver implements ObserverInterface
{
@@ -96,6 +98,8 @@ public function execute(\Magento\Framework\Event\Observer $observer)
}
if (!$cart || $cart->getItemsCount() == 0) {
+ $this->customerSession->setCustomerId(null)
+ ->setCustomerGroupId(null);
$this->quoteManager->setGuest();
}
}
diff --git a/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php b/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php
index 0c183084edca2..03d6ab02beb3c 100644
--- a/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php
+++ b/app/code/Magento/Persistent/Test/Unit/Model/QuoteManagerTest.php
@@ -9,6 +9,8 @@
namespace Magento\Persistent\Test\Unit\Model;
use Magento\Checkout\Model\Session;
+use Magento\Customer\Api\Data\CustomerInterface;
+use Magento\Customer\Api\Data\CustomerInterfaceFactory;
use Magento\Customer\Model\GroupManagement;
use Magento\Eav\Model\Entity\Collection\AbstractCollection;
use Magento\Persistent\Helper\Data;
@@ -78,6 +80,11 @@ class QuoteManagerTest extends TestCase
*/
private $shippingAssignmentProcessor;
+ /**
+ * @var CustomerInterfaceFactory|MockObject
+ */
+ private $customerDataFactory;
+
protected function setUp(): void
{
$this->persistentSessionMock = $this->createMock(\Magento\Persistent\Helper\Session::class);
@@ -124,13 +131,15 @@ protected function setUp(): void
'getItemsQty',
'getExtensionAttributes',
'setExtensionAttributes',
- '__wakeup'
+ '__wakeup',
+ 'setCustomer'
])
->disableOriginalConstructor()
->getMock();
$this->cartExtensionFactory = $this->createPartialMock(CartExtensionFactory::class, ['create']);
$this->shippingAssignmentProcessor = $this->createPartialMock(ShippingAssignmentProcessor::class, ['create']);
+ $this->customerDataFactory = $this->createMock(CustomerInterfaceFactory::class);
$this->model = new QuoteManager(
$this->persistentSessionMock,
@@ -138,7 +147,8 @@ protected function setUp(): void
$this->checkoutSessionMock,
$this->quoteRepositoryMock,
$this->cartExtensionFactory,
- $this->shippingAssignmentProcessor
+ $this->shippingAssignmentProcessor,
+ $this->customerDataFactory
);
}
@@ -189,6 +199,7 @@ public function testSetGuestWhenShoppingCartAndQuoteAreNotPersistent()
public function testSetGuest()
{
+ $customerId = 22;
$this->checkoutSessionMock->expects($this->once())
->method('getQuote')->willReturn($this->quoteMock);
$this->quoteMock->expects($this->once())->method('getId')->willReturn(11);
@@ -220,6 +231,7 @@ public function testSetGuest()
->method('getShippingAddress')->willReturn($quoteAddressMock);
$this->quoteMock->expects($this->once())
->method('getBillingAddress')->willReturn($quoteAddressMock);
+ $this->quoteMock->method('getCustomerId')->willReturn($customerId);
$this->quoteMock->expects($this->once())->method('collectTotals')->willReturn($this->quoteMock);
$this->quoteRepositoryMock->expects($this->once())->method('save')->with($this->quoteMock);
$this->persistentSessionMock->expects($this->once())
@@ -229,7 +241,6 @@ public function testSetGuest()
$this->quoteMock->expects($this->once())->method('isVirtual')->willReturn(false);
$this->quoteMock->expects($this->once())->method('getItemsQty')->willReturn(1);
$extensionAttributes = $this->getMockBuilder(CartExtensionInterface::class)
- ->addMethods(['getShippingAssignments', 'setShippingAssignments'])
->getMockForAbstractClass();
$shippingAssignment = $this->createMock(ShippingAssignmentInterface::class);
$extensionAttributes->expects($this->once())
@@ -248,6 +259,11 @@ public function testSetGuest()
$this->quoteMock->expects($this->once())
->method('setExtensionAttributes')
->with($extensionAttributes);
+ $customerMock = $this->createMock(CustomerInterface::class);
+ $this->customerDataFactory->method('create')->willReturn($customerMock);
+ $this->quoteMock->expects($this->once())
+ ->method('setCustomer')
+ ->with($customerMock);
$this->model->setGuest(false);
}
diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/MakePersistentQuoteGuestObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/MakePersistentQuoteGuestObserverTest.php
index 3622fe66099a4..bb78447cf852f 100644
--- a/app/code/Magento/Persistent/Test/Unit/Observer/MakePersistentQuoteGuestObserverTest.php
+++ b/app/code/Magento/Persistent/Test/Unit/Observer/MakePersistentQuoteGuestObserverTest.php
@@ -1,6 +1,5 @@
actionMock = $this->createMock(Index::class);
@@ -67,7 +69,7 @@ protected function setUp(): void
$this->sessionHelperMock = $this->createMock(Session::class);
$this->helperMock = $this->createMock(Data::class);
$this->customerSessionMock = $this->createMock(\Magento\Customer\Model\Session::class);
- $this->quoteManagerMock = $this->createMock(QuoteManager::class);
+ $this->checkoutSession = $this->createMock(CheckoutSession::class);
$this->eventManagerMock =
$this->getMockBuilder(Event::class)
->addMethods(['getControllerAction'])
@@ -81,7 +83,7 @@ protected function setUp(): void
$this->sessionHelperMock,
$this->helperMock,
$this->customerSessionMock,
- $this->quoteManagerMock
+ $this->checkoutSession
);
}
@@ -94,7 +96,8 @@ public function testExecute()
$this->sessionHelperMock->expects($this->once())->method('isPersistent')->willReturn(true);
$this->customerSessionMock->expects($this->once())->method('isLoggedIn')->willReturn(false);
$this->helperMock->expects($this->never())->method('isShoppingCartPersist');
- $this->quoteManagerMock->expects($this->once())->method('setGuest')->with(true);
+ $this->checkoutSession->expects($this->once())->method('clearQuote')->willReturnSelf();
+ $this->checkoutSession->expects($this->once())->method('clearStorage')->willReturnSelf();
$this->model->execute($this->observerMock);
}
@@ -107,7 +110,8 @@ public function testExecuteWhenShoppingCartIsPersist()
$this->sessionHelperMock->expects($this->once())->method('isPersistent')->willReturn(true);
$this->customerSessionMock->expects($this->once())->method('isLoggedIn')->willReturn(true);
$this->helperMock->expects($this->once())->method('isShoppingCartPersist')->willReturn(true);
- $this->quoteManagerMock->expects($this->once())->method('setGuest')->with(true);
+ $this->checkoutSession->expects($this->once())->method('clearQuote')->willReturnSelf();
+ $this->checkoutSession->expects($this->once())->method('clearStorage')->willReturnSelf();
$this->model->execute($this->observerMock);
}
@@ -120,7 +124,8 @@ public function testExecuteWhenShoppingCartIsNotPersist()
$this->sessionHelperMock->expects($this->once())->method('isPersistent')->willReturn(true);
$this->customerSessionMock->expects($this->once())->method('isLoggedIn')->willReturn(true);
$this->helperMock->expects($this->once())->method('isShoppingCartPersist')->willReturn(false);
- $this->quoteManagerMock->expects($this->never())->method('setGuest');
+ $this->checkoutSession->expects($this->never())->method('clearQuote')->willReturnSelf();
+ $this->checkoutSession->expects($this->never())->method('clearStorage')->willReturnSelf();
$this->model->execute($this->observerMock);
}
}
diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/RemoveGuestPersistenceOnEmptyCartObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/RemoveGuestPersistenceOnEmptyCartObserverTest.php
index 4adc806fed415..7bef8feaaacc5 100644
--- a/app/code/Magento/Persistent/Test/Unit/Observer/RemoveGuestPersistenceOnEmptyCartObserverTest.php
+++ b/app/code/Magento/Persistent/Test/Unit/Observer/RemoveGuestPersistenceOnEmptyCartObserverTest.php
@@ -137,6 +137,13 @@ public function testExecuteWithEmptyCart()
->with($customerId)
->willReturn($quoteMock);
$quoteMock->expects($this->once())->method('getItemsCount')->willReturn($emptyCount);
+ $this->customerSessionMock->expects($this->once())
+ ->method('setCustomerId')
+ ->with(null)
+ ->willReturnSelf();
+ $this->customerSessionMock->expects($this->once())
+ ->method('setCustomerGroupId')
+ ->with(null);
$this->quoteManagerMock->expects($this->once())->method('setGuest');
$this->model->execute($this->observerMock);
@@ -160,6 +167,13 @@ public function testExecuteWithNonexistentCart()
->method('getActiveForCustomer')
->with($customerId)
->willThrowException($exception);
+ $this->customerSessionMock->expects($this->once())
+ ->method('setCustomerId')
+ ->with(null)
+ ->willReturnSelf();
+ $this->customerSessionMock->expects($this->once())
+ ->method('setCustomerGroupId')
+ ->with(null);
$this->quoteManagerMock->expects($this->once())->method('setGuest');
$this->model->execute($this->observerMock);
diff --git a/app/code/Magento/Quote/Model/Cart/BuyRequest/BuyRequestBuilder.php b/app/code/Magento/Quote/Model/Cart/BuyRequest/BuyRequestBuilder.php
index 13b19e4f79c9a..7e8b4d916334f 100644
--- a/app/code/Magento/Quote/Model/Cart/BuyRequest/BuyRequestBuilder.php
+++ b/app/code/Magento/Quote/Model/Cart/BuyRequest/BuyRequestBuilder.php
@@ -56,6 +56,6 @@ public function build(CartItem $cartItem): DataObject
$requestData[] = $provider->execute($cartItem);
}
- return $this->dataObjectFactory->create(['data' => array_merge(...$requestData)]);
+ return $this->dataObjectFactory->create(['data' => array_merge([], ...$requestData)]);
}
}
diff --git a/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php b/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php
index 678c92250f531..ccc4735ad1763 100644
--- a/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php
+++ b/app/code/Magento/Quote/Model/Cart/Totals/ItemConverter.php
@@ -68,7 +68,7 @@ public function __construct(
}
/**
- * Converts a specified rate model to a shipping method data object.
+ * Converts a specified quote item model to a totals item data object.
*
* @param \Magento\Quote\Model\Quote\Item $item
* @return \Magento\Quote\Api\Data\TotalsItemInterface
diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php
index b0aef022dcd25..1d4b8feba07f5 100644
--- a/app/code/Magento/Quote/Model/QuoteManagement.php
+++ b/app/code/Magento/Quote/Model/QuoteManagement.php
@@ -8,6 +8,7 @@
namespace Magento\Quote\Model;
use Magento\Authorization\Model\UserContextInterface;
+use Magento\Customer\Api\Data\GroupInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Event\ManagerInterface as EventManager;
use Magento\Framework\Exception\CouldNotSaveException;
@@ -396,7 +397,8 @@ public function placeOrder($cartId, PaymentInterface $paymentMethod = null)
}
}
$quote->setCustomerIsGuest(true);
- $quote->setCustomerGroupId(\Magento\Customer\Api\Data\GroupInterface::NOT_LOGGED_IN_ID);
+ $groupId = $quote->getCustomer()->getGroupId() ?: GroupInterface::NOT_LOGGED_IN_ID;
+ $quote->setCustomerGroupId($groupId);
}
$remoteAddress = $this->remoteAddress->getRemoteAddress();
diff --git a/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php b/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php
deleted file mode 100644
index 19a7e03264d8a..0000000000000
--- a/app/code/Magento/Quote/Plugin/UpdateQuoteItemStore.php
+++ /dev/null
@@ -1,72 +0,0 @@
-quoteRepository = $quoteRepository;
- $this->checkoutSession = $checkoutSession;
- }
-
- /**
- * Update store id in active quote after store view switching.
- *
- * @param StoreSwitcherInterface $subject
- * @param string $result
- * @param StoreInterface $fromStore store where we came from
- * @param StoreInterface $targetStore store where to go to
- * @param string $redirectUrl original url requested for redirect after switching
- * @return string url to be redirected after switching
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- public function afterSwitch(
- StoreSwitcherInterface $subject,
- $result,
- StoreInterface $fromStore,
- StoreInterface $targetStore,
- string $redirectUrl
- ): string {
- $quote = $this->checkoutSession->getQuote();
- if ($quote->getIsActive()) {
- $quote->setStoreId(
- $targetStore->getId()
- );
- $quote->getItemsCollection(false);
- $this->quoteRepository->save($quote);
- }
- return $result;
- }
-}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
index ea758f7ce34f3..4197af2f2848a 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
@@ -247,6 +247,7 @@ protected function setUp(): void
'getPayment',
'setCheckoutMethod',
'setCustomerIsGuest',
+ 'getCustomer',
'getId'
]
)
@@ -799,6 +800,12 @@ public function testPlaceOrderIfCustomerIsGuest()
$this->quoteMock->expects($this->once())
->method('getCheckoutMethod')
->willReturn(Onepage::METHOD_GUEST);
+ $customerMock = $this->getMockBuilder(Customer::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->quoteMock->expects($this->once())
+ ->method('getCustomer')
+ ->willReturn($customerMock);
$this->quoteMock->expects($this->once())->method('setCustomerId')->with(null)->willReturnSelf();
$this->quoteMock->expects($this->once())->method('setCustomerEmail')->with($email)->willReturnSelf();
@@ -866,6 +873,9 @@ public function testPlaceOrderIfCustomerIsGuest()
$this->assertEquals($orderId, $service->placeOrder($cartId));
}
+ /**
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ */
public function testPlaceOrder()
{
$cartId = 323;
diff --git a/app/code/Magento/Quote/etc/frontend/di.xml b/app/code/Magento/Quote/etc/frontend/di.xml
index ecad94fbbc249..125afb96f20fd 100644
--- a/app/code/Magento/Quote/etc/frontend/di.xml
+++ b/app/code/Magento/Quote/etc/frontend/di.xml
@@ -12,9 +12,6 @@
Magento\Checkout\Model\Session\Proxy
-
-
-
diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/BuyRequest/BuyRequestBuilder.php b/app/code/Magento/QuoteGraphQl/Model/Cart/BuyRequest/BuyRequestBuilder.php
index c14cc1324732c..c4909eef31287 100644
--- a/app/code/Magento/QuoteGraphQl/Model/Cart/BuyRequest/BuyRequestBuilder.php
+++ b/app/code/Magento/QuoteGraphQl/Model/Cart/BuyRequest/BuyRequestBuilder.php
@@ -45,11 +45,11 @@ public function __construct(
*/
public function build(array $cartItemData): DataObject
{
- $requestData = [[]];
+ $requestData = [];
foreach ($this->providers as $provider) {
$requestData[] = $provider->execute($cartItemData);
}
- return $this->dataObjectFactory->create(['data' => array_merge(...$requestData)]);
+ return $this->dataObjectFactory->create(['data' => array_merge([], ...$requestData)]);
}
}
diff --git a/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/Processor/ItemDataCompositeProcessor.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/Processor/ItemDataCompositeProcessor.php
new file mode 100644
index 0000000000000..73a22471584ec
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/Processor/ItemDataCompositeProcessor.php
@@ -0,0 +1,45 @@
+itemDataProcessors = $itemDataProcessors;
+ }
+
+ /**
+ * Process cart item data
+ *
+ * @param array $cartItemData
+ * @param ContextInterface $context
+ * @return array
+ */
+ public function process(array $cartItemData, ContextInterface $context): array
+ {
+ foreach ($this->itemDataProcessors as $itemDataProcessor) {
+ $cartItemData = $itemDataProcessor->process($cartItemData, $context);
+ }
+
+ return $cartItemData;
+ }
+}
diff --git a/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/Processor/ItemDataProcessorInterface.php b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/Processor/ItemDataProcessorInterface.php
new file mode 100644
index 0000000000000..33f40bd28c1d3
--- /dev/null
+++ b/app/code/Magento/QuoteGraphQl/Model/CartItem/DataProvider/Processor/ItemDataProcessorInterface.php
@@ -0,0 +1,25 @@
+getCartForUser = $getCartForUser;
$this->addProductsToCartService = $addProductsToCart;
+ $this->itemDataProcessor = $itemDataProcessor;
}
/**
@@ -68,6 +78,9 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
$cartItems = [];
foreach ($cartItemsData as $cartItemData) {
+ if (!$this->itemIsAllowedToCart($cartItemData, $context)) {
+ continue;
+ }
$cartItems[] = (new CartItemFactory())->create($cartItemData);
}
@@ -90,4 +103,21 @@ function (Error $error) {
)
];
}
+
+ /**
+ * Check if the item can be added to cart
+ *
+ * @param array $cartItemData
+ * @param ContextInterface $context
+ * @return bool
+ */
+ private function itemIsAllowedToCart(array $cartItemData, ContextInterface $context): bool
+ {
+ $cartItemData = $this->itemDataProcessor->process($cartItemData, $context);
+ if (isset($cartItemData['grant_checkout']) && $cartItemData['grant_checkout'] === false) {
+ return false;
+ }
+
+ return true;
+ }
}
diff --git a/app/code/Magento/QuoteGraphQl/etc/di.xml b/app/code/Magento/QuoteGraphQl/etc/di.xml
index d230df253221b..35b52dd495c5a 100644
--- a/app/code/Magento/QuoteGraphQl/etc/di.xml
+++ b/app/code/Magento/QuoteGraphQl/etc/di.xml
@@ -7,6 +7,7 @@
-->
+
diff --git a/app/code/Magento/RelatedProductGraphQl/Model/Resolver/Batch/AbstractLikedProducts.php b/app/code/Magento/RelatedProductGraphQl/Model/Resolver/Batch/AbstractLikedProducts.php
index e14d8bde6be74..fac7b23d408e3 100644
--- a/app/code/Magento/RelatedProductGraphQl/Model/Resolver/Batch/AbstractLikedProducts.php
+++ b/app/code/Magento/RelatedProductGraphQl/Model/Resolver/Batch/AbstractLikedProducts.php
@@ -89,8 +89,7 @@ private function findRelations(array $products, array $loadAttributes, int $link
if (!$relations) {
return [];
}
- $relatedIds = array_values($relations);
- $relatedIds = array_unique(array_merge(...$relatedIds));
+ $relatedIds = array_unique(array_merge([], ...array_values($relations)));
//Loading products data.
$this->searchCriteriaBuilder->addFilter('entity_id', $relatedIds, 'in');
$relatedSearchResult = $this->productDataProvider->getList(
@@ -142,7 +141,7 @@ public function resolve(ContextInterface $context, Field $field, array $requests
$products[] = $request->getValue()['model'];
$fields[] = $this->productFieldsSelector->getProductFieldsFromInfo($request->getInfo(), $this->getNode());
}
- $fields = array_unique(array_merge(...$fields));
+ $fields = array_unique(array_merge([], ...$fields));
//Finding relations.
$related = $this->findRelations($products, $fields, $this->getLinkType());
diff --git a/app/code/Magento/Reports/Block/Adminhtml/Grid.php b/app/code/Magento/Reports/Block/Adminhtml/Grid.php
index 8885c94c6989a..eade7250f6123 100644
--- a/app/code/Magento/Reports/Block/Adminhtml/Grid.php
+++ b/app/code/Magento/Reports/Block/Adminhtml/Grid.php
@@ -209,7 +209,7 @@ protected function _getAllowedStoreIds()
} elseif ($this->getRequest()->getParam('website')) {
$storeIds = $this->_storeManager->getWebsite($this->getRequest()->getParam('website'))->getStoreIds();
} elseif ($this->getRequest()->getParam('group')) {
- $storeIds = $storeIds = $this->_storeManager->getGroup(
+ $storeIds = $this->_storeManager->getGroup(
$this->getRequest()->getParam('group')
)->getStoreIds();
}
diff --git a/app/code/Magento/Reports/Block/Product/Viewed.php b/app/code/Magento/Reports/Block/Product/Viewed.php
index ba4d03182213a..09d59e475905b 100644
--- a/app/code/Magento/Reports/Block/Product/Viewed.php
+++ b/app/code/Magento/Reports/Block/Product/Viewed.php
@@ -76,10 +76,10 @@ protected function _toHtml()
*/
public function getIdentities()
{
- $identities = [[]];
+ $identities = [];
foreach ($this->getItemsCollection() as $item) {
$identities[] = $item->getIdentities();
}
- return array_merge(...$identities);
+ return array_merge([], ...$identities);
}
}
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Items/Column/DefaultColumn.php b/app/code/Magento/Sales/Block/Adminhtml/Items/Column/DefaultColumn.php
index efef617acf900..81f670de91805 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Items/Column/DefaultColumn.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Items/Column/DefaultColumn.php
@@ -68,7 +68,7 @@ public function getItem()
*/
public function getOrderOptions()
{
- $result = [[]];
+ $result = [];
if ($options = $this->getItem()->getProductOptions()) {
if (isset($options['options'])) {
$result[] = $options['options'];
@@ -80,7 +80,7 @@ public function getOrderOptions()
$result[] = $options['attributes_info'];
}
}
- return array_merge(...$result);
+ return array_merge([], ...$result);
}
/**
diff --git a/app/code/Magento/Sales/Block/Order/Email/Items/DefaultItems.php b/app/code/Magento/Sales/Block/Order/Email/Items/DefaultItems.php
index cbb79f188f231..57fc0441fe830 100644
--- a/app/code/Magento/Sales/Block/Order/Email/Items/DefaultItems.php
+++ b/app/code/Magento/Sales/Block/Order/Email/Items/DefaultItems.php
@@ -39,7 +39,7 @@ public function getOrder()
*/
public function getItemOptions()
{
- $result = [[]];
+ $result = [];
if ($options = $this->getItem()->getOrderItem()->getProductOptions()) {
if (isset($options['options'])) {
$result[] = $options['options'];
@@ -52,7 +52,7 @@ public function getItemOptions()
}
}
- return array_merge(...$result);
+ return array_merge([], ...$result);
}
/**
diff --git a/app/code/Magento/Sales/Block/Order/Email/Items/Order/DefaultOrder.php b/app/code/Magento/Sales/Block/Order/Email/Items/Order/DefaultOrder.php
index 0291a1275c350..cb9c7315244ac 100644
--- a/app/code/Magento/Sales/Block/Order/Email/Items/Order/DefaultOrder.php
+++ b/app/code/Magento/Sales/Block/Order/Email/Items/Order/DefaultOrder.php
@@ -34,7 +34,7 @@ public function getOrder()
*/
public function getItemOptions()
{
- $result = [[]];
+ $result = [];
if ($options = $this->getItem()->getProductOptions()) {
if (isset($options['options'])) {
$result[] = $options['options'];
@@ -47,7 +47,7 @@ public function getItemOptions()
}
}
- return array_merge(...$result);
+ return array_merge([], ...$result);
}
/**
diff --git a/app/code/Magento/Sales/Block/Order/Item/Renderer/DefaultRenderer.php b/app/code/Magento/Sales/Block/Order/Item/Renderer/DefaultRenderer.php
index bca6d49760d9a..010878559c2f0 100644
--- a/app/code/Magento/Sales/Block/Order/Item/Renderer/DefaultRenderer.php
+++ b/app/code/Magento/Sales/Block/Order/Item/Renderer/DefaultRenderer.php
@@ -105,7 +105,7 @@ public function getOrderItem()
*/
public function getItemOptions()
{
- $result = [[]];
+ $result = [];
$options = $this->getOrderItem()->getProductOptions();
if ($options) {
if (isset($options['options'])) {
@@ -118,7 +118,7 @@ public function getItemOptions()
$result[] = $options['attributes_info'];
}
}
- return array_merge(...$result);
+ return array_merge([], ...$result);
}
/**
diff --git a/app/code/Magento/Sales/Helper/Guest.php b/app/code/Magento/Sales/Helper/Guest.php
index a3f2ac6ba3556..3b7e491086b17 100644
--- a/app/code/Magento/Sales/Helper/Guest.php
+++ b/app/code/Magento/Sales/Helper/Guest.php
@@ -15,6 +15,7 @@
/**
* Sales module base helper
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class Guest extends \Magento\Framework\App\Helper\AbstractHelper
{
@@ -71,7 +72,7 @@ class Guest extends \Magento\Framework\App\Helper\AbstractHelper
const COOKIE_NAME = 'guest-view';
/**
- * Cookie path
+ * Cookie path value
*/
const COOKIE_PATH = '/';
@@ -151,6 +152,7 @@ public function loadValidOrder(App\RequestInterface $request)
return $this->resultRedirectFactory->create()->setPath('sales/order/history');
}
$post = $request->getPostValue();
+ $post = filter_var($post, FILTER_CALLBACK, ['options' => 'trim']);
$fromCookie = $this->cookieManager->getCookie(self::COOKIE_NAME);
if (empty($post) && !$fromCookie) {
return $this->resultRedirectFactory->create()->setPath('sales/guest/form');
@@ -224,6 +226,7 @@ private function setGuestViewCookie($cookieValue)
*/
private function loadFromCookie($fromCookie)
{
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
$cookieData = explode(':', base64_decode($fromCookie));
$protectCode = isset($cookieData[0]) ? $cookieData[0] : null;
$incrementId = isset($cookieData[1]) ? $cookieData[1] : null;
diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php
index 5b9f254201bda..393d61b69bf22 100644
--- a/app/code/Magento/Sales/Model/AdminOrder/Create.php
+++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php
@@ -642,6 +642,7 @@ protected function _initShippingAddressFromOrder(\Magento\Sales\Model\Order $ord
* @param \Magento\Sales\Model\Order\Item $orderItem
* @param int $qty
* @return \Magento\Quote\Model\Quote\Item|string|$this
+ * @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function initFromOrderItem(\Magento\Sales\Model\Order\Item $orderItem, $qty = null)
{
@@ -666,10 +667,17 @@ public function initFromOrderItem(\Magento\Sales\Model\Order\Item $orderItem, $q
$productOptions = $orderItem->getProductOptions();
if ($productOptions !== null && !empty($productOptions['options'])) {
$formattedOptions = [];
+ $useFrontendCalendar = $this->useFrontendCalendar();
foreach ($productOptions['options'] as $option) {
+ if (in_array($option['option_type'], ['date', 'date_time']) && $useFrontendCalendar) {
+ $product->setSkipCheckRequiredOption(false);
+ break;
+ }
$formattedOptions[$option['option_id']] = $option['option_value'];
}
- $buyRequest->setData('options', $formattedOptions);
+ if (!empty($formattedOptions)) {
+ $buyRequest->setData('options', $formattedOptions);
+ }
}
$item = $this->getQuote()->addProduct($product, $buyRequest);
if (is_string($item)) {
@@ -2115,4 +2123,17 @@ private function isAddressesAreEqual(Order $order)
return $shippingData == $billingData;
}
+
+ /**
+ * Use Calendar on frontend or not
+ *
+ * @return bool
+ */
+ private function useFrontendCalendar(): bool
+ {
+ return (bool)$this->_scopeConfig->getValue(
+ 'catalog/custom_options/use_calendar',
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+ );
+ }
}
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
index 93c8ed00f9daa..a92a1480bd023 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Sender/EmailSender.php
@@ -111,6 +111,12 @@ public function send(
'store' => $order->getStore(),
'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+ 'order_data' => [
+ 'customer_name' => $order->getCustomerName(),
+ 'is_not_virtual' => $order->getIsNotVirtual(),
+ 'email_customer_note' => $order->getEmailCustomerNote(),
+ 'frontend_status_label' => $order->getFrontendStatusLabel()
+ ]
];
$transportObject = new DataObject($transport);
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php
index 004f36c277028..44b4df17619d8 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice/Sender/EmailSender.php
@@ -111,6 +111,12 @@ public function send(
'store' => $order->getStore(),
'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+ 'order_data' => [
+ 'customer_name' => $order->getCustomerName(),
+ 'is_not_virtual' => $order->getIsNotVirtual(),
+ 'email_customer_note' => $order->getEmailCustomerNote(),
+ 'frontend_status_label' => $order->getFrontendStatusLabel()
+ ]
];
$transportObject = new DataObject($transport);
diff --git a/app/code/Magento/Sales/Model/Order/Payment.php b/app/code/Magento/Sales/Model/Order/Payment.php
index 6a2a77b52927a..d1a34b496b1ac 100644
--- a/app/code/Magento/Sales/Model/Order/Payment.php
+++ b/app/code/Magento/Sales/Model/Order/Payment.php
@@ -742,7 +742,7 @@ public function refund($creditmemo)
$this->formatPrice($baseAmountToRefund)
);
}
- $message = $message = $this->prependMessage($message);
+ $message = $this->prependMessage($message);
$message = $this->_appendTransactionToMessage($transaction, $message);
$orderState = $this->getOrderStateResolver()->getStateForOrder($this->getOrder());
$statuses = $this->getOrder()->getConfig()->getStateStatuses($orderState, false);
diff --git a/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php b/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php
index 29e011217ef20..a7315aeb9e3be 100644
--- a/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php
+++ b/app/code/Magento/Sales/Model/Order/Pdf/Items/AbstractItems.php
@@ -326,7 +326,7 @@ public function getItemPricesForDisplay()
*/
public function getItemOptions()
{
- $result = [[]];
+ $result = [];
$options = $this->getItem()->getOrderItem()->getProductOptions();
if ($options) {
if (isset($options['options'])) {
@@ -339,7 +339,7 @@ public function getItemOptions()
$result[] = $options['attributes_info'];
}
}
- return array_merge(...$result);
+ return array_merge([], ...$result);
}
/**
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php b/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
index fe68555d9f7c7..286d33815aea1 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Sender/EmailSender.php
@@ -112,7 +112,13 @@ public function send(
'payment_html' => $this->getPaymentHtml($order),
'store' => $order->getStore(),
'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
- 'formattedBillingAddress' => $this->getFormattedBillingAddress($order)
+ 'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+ 'order_data' => [
+ 'customer_name' => $order->getCustomerName(),
+ 'is_not_virtual' => $order->getIsNotVirtual(),
+ 'email_customer_note' => $order->getEmailCustomerNote(),
+ 'frontend_status_label' => $order->getFrontendStatusLabel()
+ ]
];
$transportObject = new DataObject($transport);
diff --git a/app/code/Magento/Sales/Model/ResourceModel/EntityAbstract.php b/app/code/Magento/Sales/Model/ResourceModel/EntityAbstract.php
index 72ce60d32877c..eccfc8e56e6e5 100644
--- a/app/code/Magento/Sales/Model/ResourceModel/EntityAbstract.php
+++ b/app/code/Magento/Sales/Model/ResourceModel/EntityAbstract.php
@@ -87,7 +87,7 @@ public function __construct(
* Perform actions after object save
*
* @param \Magento\Framework\Model\AbstractModel $object
- * @param string $attribute
+ * @param AbstractAttribute|string[]|string $attribute
* @return $this
* @throws \Exception
*/
diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Status.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Status.php
index 58284759b2fee..3ff2ed66a846b 100644
--- a/app/code/Magento/Sales/Model/ResourceModel/Order/Status.php
+++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Status.php
@@ -257,7 +257,7 @@ protected function getStatusByState($state)
{
return (string)$this->getConnection()->fetchOne(
$select = $this->getConnection()->select()
- ->from(['sss' => $this->stateTable, []])
+ ->from(['sss' => $this->stateTable], [])
->where('state = ?', $state)
->limit(1)
->columns(['status'])
diff --git a/app/code/Magento/Sales/Model/ResourceModel/Provider/NotSyncedDataProvider.php b/app/code/Magento/Sales/Model/ResourceModel/Provider/NotSyncedDataProvider.php
index 645e411b80b67..10b3ca1bde996 100644
--- a/app/code/Magento/Sales/Model/ResourceModel/Provider/NotSyncedDataProvider.php
+++ b/app/code/Magento/Sales/Model/ResourceModel/Provider/NotSyncedDataProvider.php
@@ -37,11 +37,11 @@ public function __construct(TMapFactory $tmapFactory, array $providers = [])
*/
public function getIds($mainTableName, $gridTableName)
{
- $result = [[]];
+ $result = [];
foreach ($this->providers as $provider) {
$result[] = $provider->getIds($mainTableName, $gridTableName);
}
- return array_unique(array_merge(...$result));
+ return array_unique(array_merge([], ...$result));
}
}
diff --git a/app/code/Magento/Sales/Model/ShipOrder.php b/app/code/Magento/Sales/Model/ShipOrder.php
index 26fe5a8e4b457..f955f6574a7b2 100644
--- a/app/code/Magento/Sales/Model/ShipOrder.php
+++ b/app/code/Magento/Sales/Model/ShipOrder.php
@@ -177,11 +177,13 @@ public function execute(
$connection->beginTransaction();
try {
$this->orderRegistrar->register($order, $shipment);
- $order->setState(
- $this->orderStateResolver->getStateForOrder($order, [OrderStateResolverInterface::IN_PROGRESS])
- );
- $order->setStatus($this->config->getStateDefaultStatus($order->getState()));
- $shippingData = $this->shipmentRepository->save($shipment);
+ $shipment = $this->shipmentRepository->save($shipment);
+ if ($order->getState() === Order::STATE_NEW) {
+ $order->setState(
+ $this->orderStateResolver->getStateForOrder($order, [OrderStateResolverInterface::IN_PROGRESS])
+ );
+ $order->setStatus($this->config->getStateDefaultStatus($order->getState()));
+ }
$this->orderRepository->save($order);
$connection->commit();
} catch (\Exception $e) {
@@ -191,9 +193,7 @@ public function execute(
__('Could not save a shipment, see error log for details')
);
}
- if ($shipment && empty($shipment->getEntityId())) {
- $shipment->setEntityId($shippingData->getEntityId());
- }
+
if ($notify) {
if (!$appendComment) {
$comment = null;
diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminAssertOrderShippingMethodActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminAssertOrderShippingMethodActionGroup.xml
new file mode 100644
index 0000000000000..d6d5c9e7315d9
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminAssertOrderShippingMethodActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Assert that shipping method and shipping price is present for the order.
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminSelectFieldToColumnActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminSelectFieldToColumnActionGroup.xml
new file mode 100644
index 0000000000000..361787948a133
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminSelectFieldToColumnActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Select or clear the checkbox to display the column on the Orders grid page.
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/StorefrontFillOrdersAndReturnsFormTypeZipActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/StorefrontFillOrdersAndReturnsFormTypeZipActionGroup.xml
new file mode 100644
index 0000000000000..ad7f5011af954
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/StorefrontFillOrdersAndReturnsFormTypeZipActionGroup.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Sales/Test/Mftf/Data/AddressData.xml
index 920618a70dfb8..f96028405c4e5 100644
--- a/app/code/Magento/Sales/Test/Mftf/Data/AddressData.xml
+++ b/app/code/Magento/Sales/Test/Mftf/Data/AddressData.xml
@@ -24,6 +24,7 @@
78758
joe.buyer@email.com
512-345-6789
+ United States
Joe
@@ -41,5 +42,6 @@
78758
joe.buyer@email.com
512-345-6789
+ United States
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml
index a18ca0c415567..02878e79f3d70 100644
--- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml
+++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml
@@ -18,6 +18,7 @@
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontGuestOrderSearchSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontGuestOrderSearchSection.xml
index 5e420ee03bf75..efee68f2bd25f 100644
--- a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontGuestOrderSearchSection.xml
+++ b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontGuestOrderSearchSection.xml
@@ -13,6 +13,7 @@
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderOrderWithOfflinePaymentMethodTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderOrderWithOfflinePaymentMethodTest.xml
new file mode 100644
index 0000000000000..874164fdcdcf0
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminReorderOrderWithOfflinePaymentMethodTest.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminVerifyFieldToFilterOnOrdersGridTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminVerifyFieldToFilterOnOrdersGridTest.xml
new file mode 100644
index 0000000000000..b0c6b3a2fc6ca
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminVerifyFieldToFilterOnOrdersGridTest.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml
index 20dcb262b5831..b2bdf8ce5d90b 100644
--- a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml
+++ b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml
@@ -39,8 +39,7 @@
-
-
+
diff --git a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontPrintOrderFindByZipGuestTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontPrintOrderFindByZipGuestTest.xml
new file mode 100644
index 0000000000000..c99a02750d6ce
--- /dev/null
+++ b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontPrintOrderFindByZipGuestTest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php b/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php
index 0ee1e4249e27d..07f740f7c1fd8 100644
--- a/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Helper/GuestTest.php
@@ -112,7 +112,6 @@ protected function setUp(): void
->setMethods(['getTotalCount', 'getItems'])
->disableOriginalConstructor()
->getMockForAbstractClass();
- $this->searchCriteriaBuilder->method('addFilter')->willReturnSelf();
$resultRedirectFactory =
$this->getMockBuilder(RedirectFactory::class)
->setMethods(['create'])
@@ -148,29 +147,45 @@ protected function setUp(): void
);
}
- public function testLoadValidOrderNotEmptyPost()
+ /**
+ * Test load valid order with non empty post data.
+ *
+ * @param array $post
+ * @dataProvider loadValidOrderNotEmptyPostDataProvider
+ * @throws \Magento\Framework\Exception\InputException
+ * @throws \Magento\Framework\Stdlib\Cookie\CookieSizeLimitReachedException
+ * @throws \Magento\Framework\Stdlib\Cookie\FailureToSendException
+ */
+ public function testLoadValidOrderNotEmptyPost($post)
{
- $post = [
- 'oar_order_id' => 1,
- 'oar_type' => 'email',
- 'oar_billing_lastname' => 'oar_billing_lastname',
- 'oar_email' => 'oar_email',
- 'oar_zip' => 'oar_zip',
-
- ];
$incrementId = $post['oar_order_id'];
$protectedCode = 'protectedCode';
$this->sessionMock->expects($this->once())->method('isLoggedIn')->willReturn(false);
$requestMock = $this->createMock(Http::class);
$requestMock->expects($this->once())->method('getPostValue')->willReturn($post);
+
+ $this->searchCriteriaBuilder
+ ->expects($this->at(0))
+ ->method('addFilter')
+ ->with('increment_id', trim($incrementId))
+ ->willReturnSelf();
+
+ $this->searchCriteriaBuilder
+ ->expects($this->at(1))
+ ->method('addFilter')
+ ->with('store_id', $this->storeModelMock->getId())
+ ->willReturnSelf();
+
$this->salesOrderMock->expects($this->any())->method('getId')->willReturn($incrementId);
$billingAddressMock = $this->createPartialMock(
Address::class,
- ['getLastname', 'getEmail']
+ ['getLastname', 'getEmail', 'getPostcode']
);
- $billingAddressMock->expects($this->once())->method('getLastname')->willReturn(($post['oar_billing_lastname']));
- $billingAddressMock->expects($this->once())->method('getEmail')->willReturn(($post['oar_email']));
+ $billingAddressMock->expects($this->once())->method('getLastname')
+ ->willReturn(trim($post['oar_billing_lastname']));
+ $billingAddressMock->expects($this->any())->method('getEmail')->willReturn(trim($post['oar_email']));
+ $billingAddressMock->expects($this->any())->method('getPostcode')->willReturn(trim($post['oar_zip']));
$this->salesOrderMock->expects($this->once())->method('getBillingAddress')->willReturn($billingAddressMock);
$this->salesOrderMock->expects($this->once())->method('getProtectCode')->willReturn($protectedCode);
$metaDataMock = $this->createMock(PublicCookieMetadata::class);
@@ -190,10 +205,49 @@ public function testLoadValidOrderNotEmptyPost()
$this->assertTrue($this->guest->loadValidOrder($requestMock));
}
+ /**
+ * Load valid order with non empty post data provider.
+ *
+ * @return array
+ */
+ public function loadValidOrderNotEmptyPostDataProvider()
+ {
+ return [
+ [
+ [
+ 'oar_order_id' => '1',
+ 'oar_type' => 'email',
+ 'oar_billing_lastname' => 'White',
+ 'oar_email' => 'test@magento-test.com',
+ 'oar_zip' => '',
+
+ ]
+ ],
+ [
+ [
+ 'oar_order_id' => ' 14 ',
+ 'oar_type' => 'email',
+ 'oar_billing_lastname' => 'Black ',
+ 'oar_email' => ' test1@magento-test.com ',
+ 'oar_zip' => '',
+ ]
+ ],
+ [
+ [
+ 'oar_order_id' => ' 14 ',
+ 'oar_type' => 'zip',
+ 'oar_billing_lastname' => 'Black ',
+ 'oar_email' => ' test1@magento-test.com ',
+ 'oar_zip' => '123456 ',
+ ]
+ ]
+ ];
+ }
+
public function testLoadValidOrderStoredCookie()
{
$protectedCode = 'protectedCode';
- $incrementId = 1;
+ $incrementId = '1';
$cookieData = $protectedCode . ':' . $incrementId;
$cookieDataHash = base64_encode($cookieData);
$this->sessionMock->expects($this->once())->method('isLoggedIn')->willReturn(false);
@@ -201,6 +255,19 @@ public function testLoadValidOrderStoredCookie()
->method('getCookie')
->with(Guest::COOKIE_NAME)
->willReturn($cookieDataHash);
+
+ $this->searchCriteriaBuilder
+ ->expects($this->at(0))
+ ->method('addFilter')
+ ->with('increment_id', trim($incrementId))
+ ->willReturnSelf();
+
+ $this->searchCriteriaBuilder
+ ->expects($this->at(1))
+ ->method('addFilter')
+ ->with('store_id', $this->storeModelMock->getId())
+ ->willReturnSelf();
+
$this->salesOrderMock->expects($this->any())->method('getId')->willReturn($incrementId);
$this->salesOrderMock->expects($this->once())->method('getProtectCode')->willReturn($protectedCode);
$metaDataMock = $this->createMock(PublicCookieMetadata::class);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
index 99e00a74f1ba3..8bc739e9c68fd 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Sender/EmailSenderTest.php
@@ -273,6 +273,11 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
->method('setSendEmail')
->with($emailSendingResult);
+ $this->orderMock->method('getCustomerName')->willReturn('Customer name');
+ $this->orderMock->method('getIsNotVirtual')->willReturn(true);
+ $this->orderMock->method('getEmailCustomerNote')->willReturn(null);
+ $this->orderMock->method('getFrontendStatusLabel')->willReturn('Pending');
+
if (!$configValue || $forceSyncMode) {
$transport = [
'order' => $this->orderMock,
@@ -283,6 +288,12 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
'store' => $this->storeMock,
'formattedShippingAddress' => 'Formatted address',
'formattedBillingAddress' => 'Formatted address',
+ 'order_data' => [
+ 'customer_name' => 'Customer name',
+ 'is_not_virtual' => true,
+ 'email_customer_note' => null,
+ 'frontend_status_label' => 'Pending',
+ ],
];
$transport = new DataObject($transport);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php
index eaf57ad1bfc56..4a909a21e2558 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Sender/EmailSenderTest.php
@@ -272,6 +272,11 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
->method('setSendEmail')
->with($emailSendingResult);
+ $this->orderMock->method('getCustomerName')->willReturn('Customer name');
+ $this->orderMock->method('getIsNotVirtual')->willReturn(true);
+ $this->orderMock->method('getEmailCustomerNote')->willReturn(null);
+ $this->orderMock->method('getFrontendStatusLabel')->willReturn('Pending');
+
if (!$configValue || $forceSyncMode) {
$transport = [
'order' => $this->orderMock,
@@ -282,6 +287,12 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
'store' => $this->storeMock,
'formattedShippingAddress' => 'Formatted address',
'formattedBillingAddress' => 'Formatted address',
+ 'order_data' => [
+ 'customer_name' => 'Customer name',
+ 'is_not_virtual' => true,
+ 'email_customer_note' => null,
+ 'frontend_status_label' => 'Pending',
+ ],
];
$transport = new DataObject($transport);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
index 81ed71ae7bb67..713b38f7d7f4a 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/Sender/EmailSenderTest.php
@@ -284,6 +284,11 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
->method('setSendEmail')
->with($emailSendingResult);
+ $this->orderMock->method('getCustomerName')->willReturn('Customer name');
+ $this->orderMock->method('getIsNotVirtual')->willReturn(true);
+ $this->orderMock->method('getEmailCustomerNote')->willReturn(null);
+ $this->orderMock->method('getFrontendStatusLabel')->willReturn('Pending');
+
if (!$configValue || $forceSyncMode) {
$transport = [
'order' => $this->orderMock,
@@ -296,6 +301,12 @@ public function testSend($configValue, $forceSyncMode, $isComment, $emailSending
'store' => $this->storeMock,
'formattedShippingAddress' => 'Formatted address',
'formattedBillingAddress' => 'Formatted address',
+ 'order_data' => [
+ 'customer_name' => 'Customer name',
+ 'is_not_virtual' => true,
+ 'email_customer_note' => null,
+ 'frontend_status_label' => 'Pending',
+ ],
];
$transport = new DataObject($transport);
diff --git a/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
index 5909ebd76feb1..77cd6a058df6f 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/ShipOrderTest.php
@@ -270,12 +270,12 @@ public function testExecute($orderId, $items, $notify, $appendComment)
->method('setState')
->with(Order::STATE_PROCESSING)
->willReturnSelf();
- $this->orderMock->expects($this->once())
+ $this->orderMock->expects($this->exactly(2))
->method('getState')
- ->willReturn(Order::STATE_PROCESSING);
+ ->willReturn(Order::STATE_NEW);
$this->configMock->expects($this->once())
->method('getStateDefaultStatus')
- ->with(Order::STATE_PROCESSING)
+ ->with(Order::STATE_NEW)
->willReturn('Processing');
$this->orderMock->expects($this->once())
->method('setStatus')
@@ -294,7 +294,7 @@ public function testExecute($orderId, $items, $notify, $appendComment)
->method('notify')
->with($this->orderMock, $this->shipmentMock, $this->shipmentCommentCreationMock);
}
- $this->shipmentMock->expects($this->exactly(2))
+ $this->shipmentMock->expects($this->exactly(1))
->method('getEntityId')
->willReturn(2);
$this->assertEquals(
diff --git a/app/code/Magento/Sales/etc/db_schema.xml b/app/code/Magento/Sales/etc/db_schema.xml
index de062029fb53b..ab524a0f552f6 100644
--- a/app/code/Magento/Sales/etc/db_schema.xml
+++ b/app/code/Magento/Sales/etc/db_schema.xml
@@ -769,7 +769,7 @@
-
Purchased From
store_id
- componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml
index f6b1240402477..9105b4be8cda2 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_grid.xml
@@ -53,7 +53,7 @@
store_id
- ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml
index 1e60e4a806fce..c88bc91a16641 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_invoice_grid.xml
@@ -42,7 +42,7 @@
store_id
- componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml
index 9e02c31a20635..f6474b5db2fd8 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_shipment_grid.xml
@@ -42,7 +42,7 @@
store_id
- ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml
index cf536c27a0ac3..09be15c5a3cf9 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_creditmemo_grid.xml
@@ -51,7 +51,7 @@
store_id
- ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml
index ac1233c5e4961..4b6c8b3518e06 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_invoice_grid.xml
@@ -51,7 +51,7 @@
store_id
- ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml
index 5f8ebde290664..8a11bc63a4318 100644
--- a/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml
+++ b/app/code/Magento/Sales/view/adminhtml/ui_component/sales_order_view_shipment_grid.xml
@@ -51,7 +51,7 @@
store_id
- ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js
index a329524c58d41..8f13e6d9dab0d 100644
--- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js
+++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js
@@ -1507,12 +1507,17 @@ define([
if (action === 'change') {
var confirmText = message.replace(/%s/, customerGroupOption.text);
confirmText = confirmText.replace(/%s/, currentCustomerGroupTitle);
- if (confirm(confirmText)) {
- $$('#' + groupIdHtmlId + ' option').each(function (o) {
- o.selected = o.readAttribute('value') == groupId;
- });
- this.accountGroupChange();
- }
+ confirm({
+ content: confirmText,
+ actions: {
+ confirm: function() {
+ $$('#' + groupIdHtmlId + ' option').each(function (o) {
+ o.selected = o.readAttribute('value') == groupId;
+ });
+ this.accountGroupChange();
+ }.bind(this)
+ }
+ })
} else if (action === 'inform') {
alert({
content: message + '\n' + groupMessage
diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminOpenCartPriceRulesPageActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminOpenCartPriceRulesPageActionGroup.xml
new file mode 100644
index 0000000000000..b12bdf56e0ed8
--- /dev/null
+++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/AdminOpenCartPriceRulesPageActionGroup.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ Open cart price rules page.
+
+
+
+
+
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateBuyXGetYFreeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateBuyXGetYFreeTest.xml
index ed2dd16b7df9d..5f2b40dc63e2a 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateBuyXGetYFreeTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateBuyXGetYFreeTest.xml
@@ -34,8 +34,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionAndFreeShippingIsAppliedTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionAndFreeShippingIsAppliedTest.xml
index 34152ea06745c..88853b2c40d9a 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionAndFreeShippingIsAppliedTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionAndFreeShippingIsAppliedTest.xml
@@ -31,8 +31,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionIsNotAppliedTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionIsNotAppliedTest.xml
index 9ac73ceae586e..25d9d431d1c51 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionIsNotAppliedTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleAndVerifyRuleConditionIsNotAppliedTest.xml
@@ -33,8 +33,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml
index f956d036d7080..e206633808057 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleEmptyFromDateTest.xml
@@ -47,8 +47,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForCouponCodeTest.xml
index 557a585858868..16af210066997 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForCouponCodeTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForCouponCodeTest.xml
@@ -34,8 +34,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForGeneratedCouponTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForGeneratedCouponTest.xml
index 953d142a49ab1..79672b5bdd559 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForGeneratedCouponTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForGeneratedCouponTest.xml
@@ -34,8 +34,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForMatchingSubtotalAndVerifyRuleConditionIsAppliedTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForMatchingSubtotalAndVerifyRuleConditionIsAppliedTest.xml
index 34714e9637d46..da8c8e4bc1f9d 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForMatchingSubtotalAndVerifyRuleConditionIsAppliedTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleForMatchingSubtotalAndVerifyRuleConditionIsAppliedTest.xml
@@ -31,8 +31,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingCategoryAndVerifyRuleConditionIsAppliedTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingCategoryAndVerifyRuleConditionIsAppliedTest.xml
index a3e6331e31cf6..f6e736c73db74 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingCategoryAndVerifyRuleConditionIsAppliedTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingCategoryAndVerifyRuleConditionIsAppliedTest.xml
@@ -38,8 +38,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingTotalWeightAndVerifyRuleConditionIsAppliedTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingTotalWeightAndVerifyRuleConditionIsAppliedTest.xml
index e9f7f3ec6c70a..5f110f7074f6f 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingTotalWeightAndVerifyRuleConditionIsAppliedTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateCartPriceRuleWithMatchingTotalWeightAndVerifyRuleConditionIsAppliedTest.xml
@@ -31,8 +31,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountDiscountTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountDiscountTest.xml
index 0d98abfba3f62..2c3574906848c 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountDiscountTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountDiscountTest.xml
@@ -34,8 +34,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountWholeCartDiscountTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountWholeCartDiscountTest.xml
index bc4139435ab55..1b24480b5808b 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountWholeCartDiscountTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateFixedAmountWholeCartDiscountTest.xml
@@ -34,8 +34,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateInvalidRuleTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateInvalidRuleTest.xml
index 56c4506196d24..83648cec149d0 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateInvalidRuleTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreateInvalidRuleTest.xml
@@ -26,8 +26,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreatePercentOfProductPriceTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreatePercentOfProductPriceTest.xml
index 23e472518ba84..724860b12603c 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreatePercentOfProductPriceTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/AdminCreatePercentOfProductPriceTest.xml
@@ -36,8 +36,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/CartPriceRuleForConfigurableProductTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/CartPriceRuleForConfigurableProductTest.xml
index ad1ff69a60901..d60a81dcdcef9 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/CartPriceRuleForConfigurableProductTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/CartPriceRuleForConfigurableProductTest.xml
@@ -96,8 +96,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml
index 631c516153fa2..96b3990dfd063 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml
@@ -40,8 +40,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountryTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountryTest.xml
index eef5dadfbe5d8..ea96fa41e5cad 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountryTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleCountryTest.xml
@@ -37,8 +37,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleForBundleProductTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleForBundleProductTest.xml
index c5f4e8a07f622..56486d2331bd6 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleForBundleProductTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleForBundleProductTest.xml
@@ -107,8 +107,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcodeTest.xml
index 69097e3269fcb..62c494b988bbd 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcodeTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRulePostcodeTest.xml
@@ -37,8 +37,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleQuantityTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleQuantityTest.xml
index 18057965c28e1..70ed09df7a2cc 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleQuantityTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleQuantityTest.xml
@@ -38,8 +38,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleStateTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleStateTest.xml
index c13b74b6990d0..da9ca9055d31b 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleStateTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleStateTest.xml
@@ -37,8 +37,7 @@
-
-
+
diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleSubtotalTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleSubtotalTest.xml
index 97b75ae772f08..ce0d814e50308 100644
--- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleSubtotalTest.xml
+++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontCartPriceRuleSubtotalTest.xml
@@ -38,8 +38,7 @@
-
-
+
diff --git a/app/code/Magento/Search/Model/Autocomplete.php b/app/code/Magento/Search/Model/Autocomplete.php
index 45957e8795744..57364e4c36bde 100644
--- a/app/code/Magento/Search/Model/Autocomplete.php
+++ b/app/code/Magento/Search/Model/Autocomplete.php
@@ -30,11 +30,11 @@ public function __construct(
*/
public function getItems()
{
- $data = [[]];
+ $data = [];
foreach ($this->dataProviders as $dataProvider) {
$data[] = $dataProvider->getItems();
}
- return array_merge(...$data);
+ return array_merge([], ...$data);
}
}
diff --git a/app/code/Magento/Search/Model/SynonymAnalyzer.php b/app/code/Magento/Search/Model/SynonymAnalyzer.php
index eea6a950d7ce5..16d0b0b4ddcd9 100644
--- a/app/code/Magento/Search/Model/SynonymAnalyzer.php
+++ b/app/code/Magento/Search/Model/SynonymAnalyzer.php
@@ -42,6 +42,7 @@ public function __construct(SynonymReader $synReader)
* 3 => [ 0 => "british", 1 => "english" ],
* 4 => [ 0 => "queen", 1 => "monarch" ]
* ]
+ *
* @param string $phrase
* @return array
* @throws \Magento\Framework\Exception\LocalizedException
@@ -136,6 +137,9 @@ private function getSearchPattern(array $words): string
{
$patterns = [];
for ($lastItem = count($words); $lastItem > 0; $lastItem--) {
+ $words = array_map(function ($word) {
+ return preg_quote($word, '/');
+ }, $words);
$phrase = implode("\s+", \array_slice($words, 0, $lastItem));
$patterns[] = '^' . $phrase . ',';
$patterns[] = ',' . $phrase . ',';
diff --git a/app/code/Magento/Search/Model/SynonymGroupRepository.php b/app/code/Magento/Search/Model/SynonymGroupRepository.php
index dbc2b66b1f047..c670235d67adb 100644
--- a/app/code/Magento/Search/Model/SynonymGroupRepository.php
+++ b/app/code/Magento/Search/Model/SynonymGroupRepository.php
@@ -150,7 +150,7 @@ private function create(SynonymGroupInterface $synonymGroup, $errorOnMergeConfli
*/
private function merge(SynonymGroupInterface $synonymGroupToMerge, array $matchingGroupIds)
{
- $mergedSynonyms = [[]];
+ $mergedSynonyms = [];
foreach ($matchingGroupIds as $groupId) {
/** @var SynonymGroup $synonymGroupModel */
$synonymGroupModel = $this->synonymGroupFactory->create();
@@ -160,7 +160,7 @@ private function merge(SynonymGroupInterface $synonymGroupToMerge, array $matchi
}
$mergedSynonyms[] = explode(',', $synonymGroupToMerge->getSynonymGroup());
- return array_unique(array_merge(...$mergedSynonyms));
+ return array_unique(array_merge([], ...$mergedSynonyms));
}
/**
diff --git a/app/code/Magento/Search/Test/Mftf/ActionGroup/AdminSetGlobalSearchValueActionGroup.xml b/app/code/Magento/Search/Test/Mftf/ActionGroup/AdminSetGlobalSearchValueActionGroup.xml
new file mode 100644
index 0000000000000..5bc63bf730de0
--- /dev/null
+++ b/app/code/Magento/Search/Test/Mftf/ActionGroup/AdminSetGlobalSearchValueActionGroup.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Search/Test/Mftf/Section/AdminGlobalSearchSection.xml b/app/code/Magento/Search/Test/Mftf/Section/AdminGlobalSearchSection.xml
index 0ba61283548cf..a529000e20923 100644
--- a/app/code/Magento/Search/Test/Mftf/Section/AdminGlobalSearchSection.xml
+++ b/app/code/Magento/Search/Test/Mftf/Section/AdminGlobalSearchSection.xml
@@ -11,5 +11,8 @@
diff --git a/app/code/Magento/Search/Test/Unit/Model/SynonymAnalyzerTest.php b/app/code/Magento/Search/Test/Unit/Model/SynonymAnalyzerTest.php
index 8751c8a4f3ec0..9e6d087f72f99 100644
--- a/app/code/Magento/Search/Test/Unit/Model/SynonymAnalyzerTest.php
+++ b/app/code/Magento/Search/Test/Unit/Model/SynonymAnalyzerTest.php
@@ -49,9 +49,9 @@ protected function setUp(): void
*/
public function testGetSynonymsForPhrase()
{
- $phrase = 'Elizabeth is the british queen';
+ $phrase = 'Elizabeth/Angela is the british queen';
$expected = [
- 0 => [ 0 => "Elizabeth" ],
+ 0 => [ 0 => "Elizabeth/Angela" ],
1 => [ 0 => "is" ],
2 => [ 0 => "the" ],
3 => [ 0 => "british", 1 => "english" ],
diff --git a/app/code/Magento/Search/view/adminhtml/ui_component/search_synonyms_grid.xml b/app/code/Magento/Search/view/adminhtml/ui_component/search_synonyms_grid.xml
index 42ebf1454fb7e..c95604f0afa49 100644
--- a/app/code/Magento/Search/view/adminhtml/ui_component/search_synonyms_grid.xml
+++ b/app/code/Magento/Search/view/adminhtml/ui_component/search_synonyms_grid.xml
@@ -65,7 +65,7 @@
store_id
- ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
@@ -76,7 +76,7 @@
website_id
- ns = ${ $.ns }, componentType = column, index = ${ $.index }:visible
+ ns = ${ $.ns }, index = ${ $.index }:visible
diff --git a/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php b/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php
index 618d941f7047e..edb572dfdd4d1 100644
--- a/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php
+++ b/app/code/Magento/SendFriend/Model/ResourceModel/SendFriend.php
@@ -6,10 +6,6 @@
namespace Magento\SendFriend\Model\ResourceModel;
/**
- * SendFriend Log Resource Model
- *
- * @author Magento Core Team
- *
* @api
* @since 100.0.2
*/
@@ -32,6 +28,7 @@ protected function _construct()
* @param int $ip
* @param int $startTime
* @param int $websiteId
+ *
* @return int
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
@@ -46,7 +43,7 @@ public function getSendCount($object, $ip, $startTime, $websiteId = null)
AND time>=:time
AND website_id=:website_id'
);
- $bind = ['ip' => ip2long($ip), 'time' => $startTime, 'website_id' => (int)$websiteId];
+ $bind = ['ip' => $ip, 'time' => $startTime, 'website_id' => (int)$websiteId];
$row = $connection->fetchRow($select, $bind);
return $row['count'];
@@ -58,14 +55,16 @@ public function getSendCount($object, $ip, $startTime, $websiteId = null)
* @param int $ip
* @param int $startTime
* @param int $websiteId
+ *
* @return $this
*/
public function addSendItem($ip, $startTime, $websiteId)
{
$this->getConnection()->insert(
$this->getMainTable(),
- ['ip' => ip2long($ip), 'time' => $startTime, 'website_id' => $websiteId]
+ ['ip' => $ip, 'time' => $startTime, 'website_id' => $websiteId]
);
+
return $this;
}
@@ -73,6 +72,7 @@ public function addSendItem($ip, $startTime, $websiteId)
* Delete Old logs
*
* @param int $time
+ *
* @return $this
*/
public function deleteLogsBefore($time)
diff --git a/app/code/Magento/Shipping/Test/Mftf/Data/TableRatesShippingMethodData.xml b/app/code/Magento/Shipping/Test/Mftf/Data/TableRatesShippingMethodData.xml
index 47ef68cc9d765..ceae9c546bd3b 100644
--- a/app/code/Magento/Shipping/Test/Mftf/Data/TableRatesShippingMethodData.xml
+++ b/app/code/Magento/Shipping/Test/Mftf/Data/TableRatesShippingMethodData.xml
@@ -16,4 +16,10 @@
Best Way
Table Rate
+
+
+ Weight vs. Destination
+ Price vs. Destination
+ # of Items vs. Destination
+
diff --git a/app/code/Magento/Shipping/Test/Mftf/Test/AdminCheckInputFieldsDisabledAfterAppConfigDumpTest.xml b/app/code/Magento/Shipping/Test/Mftf/Test/AdminCheckInputFieldsDisabledAfterAppConfigDumpTest.xml
index 188b12c6a91c3..0c0372850a3c4 100644
--- a/app/code/Magento/Shipping/Test/Mftf/Test/AdminCheckInputFieldsDisabledAfterAppConfigDumpTest.xml
+++ b/app/code/Magento/Shipping/Test/Mftf/Test/AdminCheckInputFieldsDisabledAfterAppConfigDumpTest.xml
@@ -13,13 +13,14 @@
-
+
+
diff --git a/app/code/Magento/Store/Controller/Store/Redirect.php b/app/code/Magento/Store/Controller/Store/Redirect.php
index 45924b5b0d28a..c20e3b31e09b1 100644
--- a/app/code/Magento/Store/Controller/Store/Redirect.php
+++ b/app/code/Magento/Store/Controller/Store/Redirect.php
@@ -21,10 +21,14 @@
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Store\Model\StoreResolver;
+use Magento\Store\Model\StoreSwitcher\ContextInterfaceFactory;
use Magento\Store\Model\StoreSwitcher\HashGenerator;
+use Magento\Store\Model\StoreSwitcher\RedirectDataGenerator;
/**
* Builds correct url to target store (group) and performs redirect.
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Redirect extends Action implements HttpGetActionInterface, HttpPostActionInterface
{
@@ -47,6 +51,14 @@ class Redirect extends Action implements HttpGetActionInterface, HttpPostActionI
* @var StoreManagerInterface
*/
private $storeManager;
+ /**
+ * @var RedirectDataGenerator|null
+ */
+ private $redirectDataGenerator;
+ /**
+ * @var ContextInterfaceFactory|null
+ */
+ private $contextFactory;
/**
* @param Context $context
@@ -55,8 +67,11 @@ class Redirect extends Action implements HttpGetActionInterface, HttpPostActionI
* @param Generic $session
* @param SidResolverInterface $sidResolver
* @param HashGenerator $hashGenerator
- * @param StoreManagerInterface $storeManager
+ * @param StoreManagerInterface|null $storeManager
+ * @param RedirectDataGenerator|null $redirectDataGenerator
+ * @param ContextInterfaceFactory|null $contextFactory
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ * @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
Context $context,
@@ -65,13 +80,19 @@ public function __construct(
Generic $session,
SidResolverInterface $sidResolver,
HashGenerator $hashGenerator,
- StoreManagerInterface $storeManager = null
+ StoreManagerInterface $storeManager = null,
+ ?RedirectDataGenerator $redirectDataGenerator = null,
+ ?ContextInterfaceFactory $contextFactory = null
) {
parent::__construct($context);
$this->storeRepository = $storeRepository;
$this->storeResolver = $storeResolver;
$this->hashGenerator = $hashGenerator;
$this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class);
+ $this->redirectDataGenerator = $redirectDataGenerator
+ ?: ObjectManager::getInstance()->get(RedirectDataGenerator::class);
+ $this->contextFactory = $contextFactory
+ ?: ObjectManager::getInstance()->get(ContextInterfaceFactory::class);
}
/**
@@ -85,7 +106,6 @@ public function execute()
$currentStore = $this->storeRepository->getById($this->storeResolver->getCurrentStoreId());
$targetStoreCode = $this->_request->getParam(StoreResolver::PARAM_NAME);
$fromStoreCode = $this->_request->getParam('___from_store');
- $error = null;
if ($targetStoreCode === null) {
return $this->_redirect($currentStore->getBaseUrl());
@@ -97,30 +117,33 @@ public function execute()
/** @var Store $targetStore */
$targetStore = $this->storeRepository->get($targetStoreCode);
$this->storeManager->setCurrentStore($targetStore);
- } catch (NoSuchEntityException $e) {
- $error = __("Requested store is not found ({$fromStoreCode})");
- }
-
- if ($error !== null) {
- $this->messageManager->addErrorMessage($error);
- $this->_redirect->redirect($this->_response, $currentStore->getBaseUrl());
- } else {
$encodedUrl = $this->_request->getParam(ActionInterface::PARAM_NAME_URL_ENCODED);
+ $redirectData = $this->redirectDataGenerator->generate(
+ $this->contextFactory->create(
+ [
+ 'fromStore' => $fromStore,
+ 'targetStore' => $targetStore,
+ 'redirectUrl' => $this->_redirect->getRedirectUrl()
+ ]
+ )
+ );
$query = [
'___from_store' => $fromStore->getCode(),
StoreResolverInterface::PARAM_NAME => $targetStoreCode,
ActionInterface::PARAM_NAME_URL_ENCODED => $encodedUrl,
+ 'data' => $redirectData->getData(),
+ 'time_stamp' => $redirectData->getTimestamp(),
+ 'signature' => $redirectData->getSignature(),
];
-
- $customerHash = $this->hashGenerator->generateHash($fromStore);
- $query = array_merge($query, $customerHash);
-
$arguments = [
'_nosid' => true,
'_query' => $query
];
$this->_redirect->redirect($this->_response, 'stores/store/switch', $arguments);
+ } catch (NoSuchEntityException $e) {
+ $this->messageManager->addErrorMessage(__("Requested store is not found ({$fromStoreCode})"));
+ $this->_redirect->redirect($this->_response, $currentStore->getBaseUrl());
}
return null;
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/Context.php b/app/code/Magento/Store/Model/StoreSwitcher/Context.php
new file mode 100644
index 0000000000000..c67dc3d67b01a
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/Context.php
@@ -0,0 +1,68 @@
+fromStore = $fromStore;
+ $this->targetStore = $targetStore;
+ $this->redirectUrl = $redirectUrl;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getFromStore(): StoreInterface
+ {
+ return $this->fromStore;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTargetStore(): StoreInterface
+ {
+ return $this->targetStore;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getRedirectUrl(): string
+ {
+ return $this->redirectUrl;
+ }
+}
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/ContextInterface.php b/app/code/Magento/Store/Model/StoreSwitcher/ContextInterface.php
new file mode 100644
index 0000000000000..a18c7cc9ccc27
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/ContextInterface.php
@@ -0,0 +1,37 @@
+hashGenerator = $hashGenerator;
$this->request = $request;
+ $this->postprocessor = $postprocessor;
+ $this->dataSerializer = $dataSerializer;
$this->messageManager = $messageManager;
- $this->customerSession = $customerSession;
- $this->customerRepository = $customerRepository;
+ $this->contextFactory = $contextFactory;
+ $this->dataFactory = $dataFactory;
+ $this->dataValidator = $dataValidator;
+ $this->logger = $logger;
}
/**
@@ -85,41 +96,39 @@ public function __construct(
*/
public function switch(StoreInterface $fromStore, StoreInterface $targetStore, string $redirectUrl): string
{
- $customerId = $this->request->getParam('customer_id');
-
- if ($customerId) {
- $fromStoreCode = (string)$this->request->getParam('___from_store');
- $timeStamp = (string)$this->request->getParam('time_stamp');
- $signature = (string)$this->request->getParam('signature');
-
- $error = null;
+ $timestamp = (int) $this->request->getParam('time_stamp');
+ $signature = (string) $this->request->getParam('signature');
+ $data = (string) $this->request->getParam('data');
+ $context = $this->contextFactory->create(
+ [
+ 'fromStore' => $fromStore,
+ 'targetStore' => $targetStore,
+ 'redirectUrl' => $redirectUrl
+ ]
+ );
+ $redirectDataObject = $this->dataFactory->create(
+ [
+ 'signature' => $signature,
+ 'timestamp' => $timestamp,
+ 'data' => $data
+ ]
+ );
- $data = new HashData(
- [
- "customer_id" => $customerId,
- "time_stamp" => $timeStamp,
- "___from_store" => $fromStoreCode
- ]
- );
-
- if ($redirectUrl && $this->hashGenerator->validateHash($signature, $data)) {
- try {
- $customer = $this->customerRepository->getById($customerId);
- if (!$this->customerSession->isLoggedIn()) {
- $this->customerSession->setCustomerDataAsLoggedIn($customer);
- }
- } catch (NoSuchEntityException $e) {
- $error = __('The requested customer does not exist.');
- } catch (LocalizedException $e) {
- $error = __('There was an error retrieving the customer record.');
- }
+ try {
+ if ($redirectUrl && $this->dataValidator->validate($context, $redirectDataObject)) {
+ $this->postprocessor->process($context, $this->dataSerializer->unserialize($data));
} else {
- $error = __('The requested store cannot be found. Please check the request and try again.');
- }
-
- if ($error !== null) {
- $this->messageManager->addErrorMessage($error);
+ throw new LocalizedException(
+ __('The requested store cannot be found. Please check the request and try again.')
+ );
}
+ } catch (LocalizedException $exception) {
+ $this->messageManager->addErrorMessage($exception->getMessage());
+ } catch (\Throwable $exception) {
+ $this->logger->error($exception);
+ $this->messageManager->addErrorMessage(
+ __('Something went wrong.')
+ );
}
return $redirectUrl;
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/RedirectData.php b/app/code/Magento/Store/Model/StoreSwitcher/RedirectData.php
new file mode 100644
index 0000000000000..58185ea3d712a
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/RedirectData.php
@@ -0,0 +1,66 @@
+signature = $signature;
+ $this->data = $data;
+ $this->timestamp = $timestamp;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getSignature(): string
+ {
+ return $this->signature;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getData(): string
+ {
+ return $this->data;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getTimestamp(): int
+ {
+ return $this->timestamp;
+ }
+}
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataCacheSerializer.php b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataCacheSerializer.php
new file mode 100644
index 0000000000000..5360d403d1388
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataCacheSerializer.php
@@ -0,0 +1,96 @@
+cache = $cache;
+ $this->json = $json;
+ $this->random = $random;
+ $this->logger = $logger;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function serialize(array $data): string
+ {
+ $token = $this->random->getRandomString(self::CACHE_ID_LENGTH);
+ $cacheKey = self::CACHE_KEY_PREFIX . $token;
+ $this->cache->save($this->json->serialize($data), $cacheKey, [], self::CACHE_LIFE_TIME);
+
+ return $token;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function unserialize(string $data): array
+ {
+ if (strlen($data) !== self::CACHE_ID_LENGTH) {
+ throw new InvalidArgumentException("Invalid cache key '$data' supplied.");
+ }
+
+ $cacheKey = self::CACHE_KEY_PREFIX . $data;
+ $json = $this->cache->load($cacheKey);
+ if (!$json) {
+ throw new InvalidArgumentException('Couldn\'t retrieve data from cache.');
+ }
+ $result = $this->json->unserialize($json);
+ try {
+ $this->cache->remove($cacheKey);
+ } catch (Throwable $exception) {
+ $this->logger->error($exception);
+ }
+
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataGenerator.php b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataGenerator.php
new file mode 100644
index 0000000000000..3ff0375a0c348
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataGenerator.php
@@ -0,0 +1,95 @@
+preprocessor = $preprocessor;
+ $this->dataSerializer = $dataSerializer;
+ $this->dataFactory = $dataFactory;
+ $this->encryptor = $encryptor;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Collect data to be redirected to the target store
+ *
+ * @param ContextInterface $context
+ * @return RedirectDataInterface
+ */
+ public function generate(ContextInterface $context): RedirectDataInterface
+ {
+ $data = $this->preprocessor->process($context, []);
+ try {
+ $dataStr = $this->dataSerializer->serialize($data);
+ } catch (\Throwable $exception) {
+ $this->logger->error($exception);
+ $dataStr = '';
+ }
+ $timestamp = time();
+ $token = implode(
+ ',',
+ [
+ $dataStr,
+ $timestamp,
+ $context->getFromStore()->getCode(),
+ $context->getTargetStore()->getCode(),
+ ]
+ );
+ $signature = $this->encryptor->hash($token, Encryptor::HASH_VERSION_SHA256);
+
+ return $this->dataFactory->create(
+ [
+ 'data' => $dataStr,
+ 'timestamp' => $timestamp,
+ 'signature' => $signature
+ ]
+ );
+ }
+}
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataInterface.php b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataInterface.php
new file mode 100644
index 0000000000000..f7fc066634b63
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataInterface.php
@@ -0,0 +1,35 @@
+processors = $processors;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process(ContextInterface $context, array $data): void
+ {
+ foreach ($this->processors as $processor) {
+ $processor->process($context, $data);
+ }
+ }
+}
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataPostprocessorInterface.php b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataPostprocessorInterface.php
new file mode 100644
index 0000000000000..de117915e23da
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataPostprocessorInterface.php
@@ -0,0 +1,22 @@
+processors = $processors;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process(ContextInterface $context, array $data): array
+ {
+ foreach ($this->processors as $processor) {
+ $data = $processor->process($context, $data);
+ }
+
+ return $data;
+ }
+}
diff --git a/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataPreprocessorInterface.php b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataPreprocessorInterface.php
new file mode 100644
index 0000000000000..d28a7dd776ab7
--- /dev/null
+++ b/app/code/Magento/Store/Model/StoreSwitcher/RedirectDataPreprocessorInterface.php
@@ -0,0 +1,23 @@
+encryptor = $encryptor;
+ }
+
+ /**
+ * Validate data redirected from origin store
+ *
+ * @param ContextInterface $context
+ * @param RedirectDataInterface $redirectData
+ * @return bool
+ */
+ public function validate(ContextInterface $context, RedirectDataInterface $redirectData)
+ {
+ $timeStamp = $redirectData->getTimestamp();
+ $signature = $redirectData->getSignature();
+ $value = implode(
+ ',',
+ [
+ $redirectData->getData(),
+ $timeStamp,
+ $context->getFromStore()->getCode(),
+ $context->getTargetStore()->getCode()
+ ]
+ );
+ return time() - $timeStamp <= self::TIMEOUT
+ && $this->encryptor->validateHash($value, $signature);
+ }
+}
diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminOpenFirstRowInStoresGridActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminOpenFirstRowInStoresGridActionGroup.xml
new file mode 100644
index 0000000000000..a3be7b0d8a8c4
--- /dev/null
+++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminOpenFirstRowInStoresGridActionGroup.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminOpenStoreInFirstRowInStoresGridActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminOpenStoreInFirstRowInStoresGridActionGroup.xml
new file mode 100644
index 0000000000000..6af4a4f159a7e
--- /dev/null
+++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminOpenStoreInFirstRowInStoresGridActionGroup.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAcceptAlertAndVerifyStoreViewFormTest.xml b/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAcceptAlertAndVerifyStoreViewFormTest.xml
index 09a33d5eb86a6..40a912617ee0b 100644
--- a/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAcceptAlertAndVerifyStoreViewFormTest.xml
+++ b/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAcceptAlertAndVerifyStoreViewFormTest.xml
@@ -51,8 +51,8 @@
-
-
+
+
diff --git a/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAndVerifyStoreViewFormTest.xml b/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAndVerifyStoreViewFormTest.xml
index 1c5d58c13538e..02125aab26496 100644
--- a/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAndVerifyStoreViewFormTest.xml
+++ b/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreGroupAndVerifyStoreViewFormTest.xml
@@ -41,8 +41,8 @@
-
-
+
+
diff --git a/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreViewTest.xml b/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreViewTest.xml
index c7c846c51af4d..b4aac676f2bc9 100644
--- a/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreViewTest.xml
+++ b/app/code/Magento/Store/Test/Mftf/Test/AdminUpdateStoreViewTest.xml
@@ -39,8 +39,8 @@
-
-
+
+
diff --git a/app/code/Magento/Store/Test/Mftf/Test/StorefrontAddStoreCodeInUrlTest.xml b/app/code/Magento/Store/Test/Mftf/Test/StorefrontAddStoreCodeInUrlTest.xml
index eaebc7fdaf74a..fc17bc7f0f10a 100644
--- a/app/code/Magento/Store/Test/Mftf/Test/StorefrontAddStoreCodeInUrlTest.xml
+++ b/app/code/Magento/Store/Test/Mftf/Test/StorefrontAddStoreCodeInUrlTest.xml
@@ -21,6 +21,9 @@
+
+
+
diff --git a/app/code/Magento/Store/Test/Unit/Controller/Store/RedirectTest.php b/app/code/Magento/Store/Test/Unit/Controller/Store/RedirectTest.php
index 91fff641338db..7d873ee6c1d8e 100755
--- a/app/code/Magento/Store/Test/Unit/Controller/Store/RedirectTest.php
+++ b/app/code/Magento/Store/Test/Unit/Controller/Store/RedirectTest.php
@@ -22,7 +22,10 @@
use Magento\Store\Model\Store;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Store\Model\StoreResolver;
+use Magento\Store\Model\StoreSwitcher\ContextInterface;
+use Magento\Store\Model\StoreSwitcher\ContextInterfaceFactory;
use Magento\Store\Model\StoreSwitcher\HashGenerator;
+use Magento\Store\Model\StoreSwitcher\RedirectDataGenerator;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
@@ -163,6 +166,11 @@ protected function setUp(): void
->method('getCurrentStoreId')
->willReturnSelf();
+ $redirectDataGenerator = $this->createMock(RedirectDataGenerator::class);
+ $contextFactory = $this->createMock(ContextInterfaceFactory::class);
+ $contextFactory->method('create')
+ ->willReturn($this->createMock(ContextInterface::class));
+
$objectManager = new ObjectManagerHelper($this);
$context = $objectManager->getObject(
Context::class,
@@ -182,6 +190,8 @@ protected function setUp(): void
'sidResolver' => $this->sidResolverMock,
'hashGenerator' => $this->hashGeneratorMock,
'context' => $context,
+ 'redirectDataGenerator' => $redirectDataGenerator,
+ 'contextFactory' => $contextFactory,
]
);
}
@@ -220,11 +230,6 @@ public function testRedirect(string $defaultStoreViewCode, string $storeCode): v
->expects($this->once())
->method('getCode')
->willReturn($defaultStoreViewCode);
- $this->hashGeneratorMock
- ->expects($this->once())
- ->method('generateHash')
- ->with($this->fromStoreMock)
- ->willReturn([]);
$this->storeManagerMock
->expects($this->once())
->method('setCurrentStore')
@@ -239,7 +244,10 @@ public function testRedirect(string $defaultStoreViewCode, string $storeCode): v
'_query' => [
'uenc' => $defaultStoreViewCode,
'___from_store' => $defaultStoreViewCode,
- '___store' => $storeCode
+ '___store' => $storeCode,
+ 'data' => '',
+ 'time_stamp' => 0,
+ 'signature' => '',
]
]
);
diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/HashProcessorTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/HashProcessorTest.php
new file mode 100644
index 0000000000000..89dc1d1c99ebd
--- /dev/null
+++ b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/HashProcessorTest.php
@@ -0,0 +1,163 @@
+request = $this->createMock(RequestInterface::class);
+ $this->postprocessor = $this->createMock(RedirectDataPostprocessorInterface::class);
+ $this->dataSerializer = $this->createMock(RedirectDataSerializerInterface::class);
+ $this->messageManager = $this->createMock(ManagerInterface::class);
+ $contextFactory = $this->createMock(ContextInterfaceFactory::class);
+ $dataFactory = $this->createMock(RedirectDataInterfaceFactory::class);
+ $this->dataValidator = $this->createMock(RedirectDataValidator::class);
+ $logger = $this->createMock(LoggerInterface::class);
+ $this->store1 = $this->createMock(StoreInterface::class);
+ $this->store2 = $this->createMock(StoreInterface::class);
+ $this->model = new HashProcessor(
+ $this->request,
+ $this->postprocessor,
+ $this->dataSerializer,
+ $this->messageManager,
+ $contextFactory,
+ $dataFactory,
+ $this->dataValidator,
+ $logger
+ );
+
+ $contextFactory->method('create')
+ ->willReturn($this->createMock(ContextInterface::class));
+ $dataFactory->method('create')
+ ->willReturnCallback(
+ function (array $data) {
+ return $this->createConfiguredMock(
+ RedirectDataInterface::class,
+ [
+ 'getTimestamp' => $data['timestamp'],
+ 'getData' => $data['data'],
+ 'getSignature' => $data['signature'],
+ ]
+ );
+ }
+ );
+ }
+
+ public function testShouldProcessIfDataValidationPassed(): void
+ {
+ $redirectUrl = '/category-1/category-1.1.html';
+ $this->request->method('getParam')
+ ->willReturnMap(
+ [
+ ['time_stamp', null, time() - 1],
+ ['data', null, '{"customer_id":1}'],
+ ['signature', null, 'randomstring'],
+ ]
+ );
+ $this->dataValidator->method('validate')
+ ->willReturn(true);
+ $this->dataSerializer->method('unserialize')
+ ->with('{"customer_id":1}')
+ ->willReturnCallback(
+ function ($arg) {
+ return json_decode($arg, true);
+ }
+ );
+ $this->postprocessor->expects($this->once())
+ ->method('process')
+ ->with($this->isInstanceOf(ContextInterface::class), ['customer_id' => 1]);
+ $this->assertEquals($redirectUrl, $this->model->switch($this->store1, $this->store2, $redirectUrl));
+ }
+
+ public function testShouldNotProcessIfDataValidationFailed(): void
+ {
+ $redirectUrl = '/category-1/category-1.1.html';
+ $this->dataValidator->method('validate')
+ ->willReturn(false);
+ $this->postprocessor->expects($this->never())
+ ->method('process');
+ $this->messageManager->expects($this->once())
+ ->method('addErrorMessage')
+ ->with('The requested store cannot be found. Please check the request and try again.');
+
+ $this->assertEquals($redirectUrl, $this->model->switch($this->store1, $this->store2, $redirectUrl));
+ }
+
+ public function testShouldNotProcessIfDataUnserializationFailed(): void
+ {
+ $redirectUrl = '/category-1/category-1.1.html';
+ $this->dataValidator->method('validate')
+ ->willReturn(true);
+ $this->dataSerializer->method('unserialize')
+ ->willThrowException(new InvalidArgumentException('Invalid token supplied'));
+ $this->postprocessor->expects($this->never())
+ ->method('process');
+ $this->messageManager->expects($this->once())
+ ->method('addErrorMessage')
+ ->with('Something went wrong.');
+
+ $this->assertEquals($redirectUrl, $this->model->switch($this->store1, $this->store2, $redirectUrl));
+ }
+}
diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataCacheSerializerTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataCacheSerializerTest.php
new file mode 100644
index 0000000000000..c21d785b268a9
--- /dev/null
+++ b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataCacheSerializerTest.php
@@ -0,0 +1,99 @@
+cache = $this->createMock(CacheInterface::class);
+ $random = $this->createMock(Random::class);
+ $logger = $this->createMock(LoggerInterface::class);
+ $this->model = new RedirectDataCacheSerializer(
+ new Json(),
+ $random,
+ $this->cache,
+ $logger
+ );
+ $random->method('getRandomString')->willReturn(self::RANDOM_STRING);
+ }
+
+ public function testSerialize(): void
+ {
+ $this->cache->expects($this->once())
+ ->method('save')
+ ->with(
+ '{"customer_id":1}',
+ 'store_switch_' . self::RANDOM_STRING,
+ [],
+ 10
+ );
+ $this->assertEquals(self::RANDOM_STRING, $this->model->serialize(['customer_id' => 1]));
+ }
+
+ public function testSerializeShouldThrowExceptionIfCannotSaveCache(): void
+ {
+ $exception = new RuntimeException('Failed to connect to cache server');
+ $this->expectExceptionObject($exception);
+ $this->cache->expects($this->once())
+ ->method('save')
+ ->willThrowException($exception);
+ $this->assertEquals(self::RANDOM_STRING, $this->model->serialize(['customer_id' => 1]));
+ }
+
+ public function testUnserialize(): void
+ {
+ $this->cache->expects($this->once())
+ ->method('load')
+ ->with('store_switch_' . self::RANDOM_STRING)
+ ->willReturn('{"customer_id":1}');
+ $this->assertEquals(['customer_id' => 1], $this->model->unserialize(self::RANDOM_STRING));
+ }
+
+ public function testUnserializeShouldThrowExceptionIfCacheHasExpired(): void
+ {
+ $this->expectExceptionObject(new InvalidArgumentException('Couldn\'t retrieve data from cache.'));
+ $this->cache->expects($this->once())
+ ->method('load')
+ ->with('store_switch_' . self::RANDOM_STRING)
+ ->willReturn(null);
+ $this->assertEquals(['customer_id' => 1], $this->model->unserialize(self::RANDOM_STRING));
+ }
+
+ public function testUnserializeShouldThrowExceptionIfCacheKeyIsInvalid(): void
+ {
+ $this->expectExceptionObject(new InvalidArgumentException('Invalid cache key \'abc\' supplied.'));
+ $this->cache->expects($this->never())
+ ->method('load');
+ $this->assertEquals(['customer_id' => 1], $this->model->unserialize('abc'));
+ }
+}
diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataGeneratorTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataGeneratorTest.php
new file mode 100644
index 0000000000000..67270f5f70dce
--- /dev/null
+++ b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataGeneratorTest.php
@@ -0,0 +1,130 @@
+preprocessor = $this->createMock(RedirectDataPreprocessorInterface::class);
+ $this->dataSerializer = $this->createMock(RedirectDataSerializerInterface::class);
+ $dataFactory = $this->createMock(RedirectDataInterfaceFactory::class);
+ $encryptor = $this->createMock(Encryptor::class);
+ $logger = $this->createMock(LoggerInterface::class);
+ $this->model = new RedirectDataGenerator(
+ $encryptor,
+ $this->preprocessor,
+ $this->dataSerializer,
+ $dataFactory,
+ $logger
+ );
+ $store1 = $this->createConfiguredMock(
+ StoreInterface::class,
+ [
+ 'getCode' => 'en',
+ 'getId' => 1,
+ ]
+ );
+ $store2 = $this->createConfiguredMock(
+ StoreInterface::class,
+ [
+ 'getCode' => 'fr',
+ 'getId' => 2,
+ ]
+ );
+ $this->context = $this->createConfiguredMock(
+ ContextInterface::class,
+ [
+ 'getFromStore' => $store2,
+ 'getTargetStore' => $store1,
+ ]
+ );
+ $encryptor->method('hash')
+ ->willReturnCallback(
+ function (string $arg1) {
+ // phpcs:ignore Magento2.Security.InsecureFunction
+ return md5($arg1);
+ }
+ );
+ $dataFactory->method('create')
+ ->willReturnCallback(
+ function (array $data) {
+ return $this->createConfiguredMock(
+ RedirectDataInterface::class,
+ [
+ 'getTimestamp' => $data['timestamp'],
+ 'getData' => $data['data'],
+ 'getSignature' => $data['signature'],
+ ]
+ );
+ }
+ );
+ }
+
+ public function testGenerate(): void
+ {
+ $this->preprocessor->method('process')
+ ->willReturn(['customer_id' => 1]);
+ $this->dataSerializer->method('serialize')
+ ->willReturnCallback('json_encode');
+ $redirectData = $this->model->generate($this->context);
+ $time = time();
+ $this->assertEqualsWithDelta($time, $redirectData->getTimestamp(), 1);
+ $time = $redirectData->getTimestamp();
+ $this->assertEquals('{"customer_id":1}', $redirectData->getData());
+ // phpcs:ignore Magento2.Security.InsecureFunction
+ $this->assertEquals(md5("{\"customer_id\":1},{$time},fr,en"), $redirectData->getSignature());
+ }
+
+ public function testShouldGenerateEmptyDataIfDataSerializationFailed(): void
+ {
+ $this->dataSerializer->method('serialize')
+ ->willThrowException(new \InvalidArgumentException('Failed to connect to cache server'));
+
+ $redirectData = $this->model->generate($this->context);
+ $time = time();
+ $this->assertEqualsWithDelta($time, $redirectData->getTimestamp(), 1);
+ $time = $redirectData->getTimestamp();
+ $this->assertEquals('', $redirectData->getData());
+ // phpcs:ignore Magento2.Security.InsecureFunction
+ $this->assertEquals(md5(",{$time},fr,en"), $redirectData->getSignature());
+ }
+}
diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataValidatorTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataValidatorTest.php
new file mode 100644
index 0000000000000..9960fad2071be
--- /dev/null
+++ b/app/code/Magento/Store/Test/Unit/Model/StoreSwitcher/RedirectDataValidatorTest.php
@@ -0,0 +1,144 @@
+createMock(Encryptor::class);
+ $this->model = new RedirectDataValidator(
+ $encryptor
+ );
+ $store1 = $this->createConfiguredMock(
+ StoreInterface::class,
+ [
+ 'getCode' => 'en',
+ 'getId' => 1,
+ ]
+ );
+ $store2 = $this->createConfiguredMock(
+ StoreInterface::class,
+ [
+ 'getCode' => 'fr',
+ 'getId' => 2,
+ ]
+ );
+ $this->context = $this->createConfiguredMock(
+ ContextInterface::class,
+ [
+ 'getFromStore' => $store2,
+ 'getTargetStore' => $store1,
+ ]
+ );
+ $encryptor->method('validateHash')
+ ->willReturnCallback(
+ function (string $value, string $hash) {
+ // phpcs:ignore Magento2.Security.InsecureFunction
+ return md5($value) === $hash;
+ }
+ );
+ }
+
+ /**
+ * @param array $params
+ * @param bool $result
+ * @dataProvider validationDataProvider
+ */
+ public function testValidation(array $params, bool $result): void
+ {
+ $originalData = '{"customer_id":1}';
+ $timestamp = time() - $params['elapsedTime'];
+ $fromStoreCode = $params['fromStoreCode'] ?? $this->context->getFromStore()->getCode();
+ $targetStoreCode = $params['targetStoreCode'] ?? $this->context->getTargetStore()->getCode();
+ // phpcs:ignore Magento2.Security.InsecureFunction
+ $signature = md5("{$originalData},{$timestamp},{$fromStoreCode},{$targetStoreCode}");
+ $redirectData = $this->createConfiguredMock(
+ RedirectDataInterface::class,
+ [
+ 'getTimestamp' => $params['timestamp'] ?? $timestamp,
+ 'getData' => $params['data'] ?? $originalData,
+ 'getSignature' => $params['signature'] ?? $signature,
+ ]
+ );
+ $this->assertEquals($result, $this->model->validate($this->context, $redirectData));
+ }
+
+ /**
+ * @return array
+ */
+ public function validationDataProvider(): array
+ {
+ return [
+ [
+ [
+ 'elapsedTime' => 1,
+ ],
+ true
+ ],
+ [
+ [
+ 'elapsedTime' => 6,
+ ],
+ false
+ ],
+ [
+ [
+ 'elapsedTime' => 1,
+ 'data' => '{"customer_id":2}'
+ ],
+ false
+ ],
+ [
+ [
+ 'elapsedTime' => 1,
+ 'fromStoreCode' => 'es'
+
+ ],
+ false
+ ],
+ [
+ [
+ 'elapsedTime' => 1,
+ 'targetStoreCode' => 'de'
+
+ ],
+ false
+ ],
+ [
+ [
+ 'elapsedTime' => 1,
+ 'signature' => 'abcd1efgh2ijkl3mnop4qrst5uvwx6yz'
+
+ ],
+ false
+ ]
+ ];
+ }
+}
diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml
index 2da9e91e1fddd..ccfec562ba103 100644
--- a/app/code/Magento/Store/etc/di.xml
+++ b/app/code/Magento/Store/etc/di.xml
@@ -26,6 +26,11 @@
+
+
+
+
+
diff --git a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php
index 939facd02c02d..612573ff493ad 100644
--- a/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php
+++ b/app/code/Magento/Tax/Model/Calculation/AbstractAggregateCalculator.php
@@ -21,7 +21,7 @@ protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $qua
$this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
);
$rate = $this->calculationTool->getRate($taxRateRequest);
- $storeRate = $storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);
+ $storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);
$discountTaxCompensationAmount = 0;
$applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
diff --git a/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php b/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php
index ed469e822d937..655fcc9749cb3 100644
--- a/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php
+++ b/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php
@@ -10,7 +10,15 @@
class UnitBaseCalculator extends AbstractCalculator
{
/**
- * {@inheritdoc}
+ * Determines the rounding operation type and rounds the amount
+ *
+ * @param float $amount
+ * @param string $rate
+ * @param bool $direction
+ * @param string $type
+ * @param bool $round
+ * @param QuoteDetailsItemInterface $item
+ * @return float|string
*/
protected function roundAmount(
$amount,
@@ -31,7 +39,12 @@ protected function roundAmount(
}
/**
- * {@inheritdoc}
+ * Calculate tax details for quote item with tax in price with given quantity
+ *
+ * @param QuoteDetailsItemInterface $item
+ * @param int $quantity
+ * @param bool $round
+ * @return \Magento\Tax\Api\Data\TaxDetailsItemInterface
*/
protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
@@ -39,7 +52,7 @@ protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $qua
$this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
);
$rate = $this->calculationTool->getRate($taxRateRequest);
- $storeRate = $storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);
+ $storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);
// Calculate $priceInclTax
$applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
@@ -104,7 +117,12 @@ protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $qua
}
/**
- * {@inheritdoc}
+ * Calculate tax details for quote item with tax not in price with given quantity
+ *
+ * @param QuoteDetailsItemInterface $item
+ * @param int $quantity
+ * @param bool $round
+ * @return \Magento\Tax\Api\Data\TaxDetailsItemInterface
*/
protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
diff --git a/app/code/Magento/Tax/Model/Plugin/OrderSave.php b/app/code/Magento/Tax/Model/Plugin/OrderSave.php
index 38952eec02ca1..b46c5b51a9db2 100644
--- a/app/code/Magento/Tax/Model/Plugin/OrderSave.php
+++ b/app/code/Magento/Tax/Model/Plugin/OrderSave.php
@@ -50,11 +50,14 @@ public function afterSave(
}
/**
+ * Save order tax
+ *
* @param \Magento\Sales\Api\Data\OrderInterface $order
* @return $this
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+ * phpcs:disable Generic.Metrics.NestingLevel.TooHigh
*/
protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order)
{
@@ -176,7 +179,9 @@ protected function saveOrderTax(\Magento\Sales\Api\Data\OrderInterface $order)
} elseif (isset($quoteItemId['associated_item_id'])) {
//This item is associated with a product item
$item = $order->getItemByQuoteItemId($quoteItemId['associated_item_id']);
- $associatedItemId = $item->getId();
+ if ($item !== null && $item->getId()) {
+ $associatedItemId = $item->getId();
+ }
}
$data = [
diff --git a/app/code/Magento/Tax/Model/ResourceModel/Calculation/Rate/Collection.php b/app/code/Magento/Tax/Model/ResourceModel/Calculation/Rate/Collection.php
index 7863b70f6626a..d34e863d56c54 100644
--- a/app/code/Magento/Tax/Model/ResourceModel/Calculation/Rate/Collection.php
+++ b/app/code/Magento/Tax/Model/ResourceModel/Calculation/Rate/Collection.php
@@ -206,7 +206,7 @@ public function getOptionRates()
{
$size = self::TAX_RULES_CHUNK_SIZE;
$page = 1;
- $rates = [[]];
+ $rates = [];
do {
$offset = $size * ($page - 1);
$this->getSelect()->reset();
@@ -222,6 +222,6 @@ public function getOptionRates()
$page++;
} while ($this->getSize() > $offset);
- return array_merge(...$rates);
+ return array_merge([], ...$rates);
}
}
diff --git a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml
index fde43cd10e3ea..fd0cb31fd8655 100644
--- a/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml
+++ b/app/code/Magento/Tax/Test/Mftf/Data/TaxRuleData.xml
@@ -123,4 +123,17 @@
TaxNameZeroRate
+
+ TaxRule
+ 0
+ 0
+
+ - 3
+
+
+ - 2
+
+
+ false
+
diff --git a/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php b/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php
index 2925ebef958b6..d98bd4a0722ee 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/Plugin/OrderSaveTest.php
@@ -175,50 +175,51 @@ public function verifyItemTaxes($expectedItemTaxes)
}
/**
+ * Test for order afterSave
+ *
* @dataProvider afterSaveDataProvider
+ * @param array $appliedTaxes
+ * @param array $itemAppliedTaxes
+ * @param array $expectedTaxes
+ * @param array $expectedItemTaxes
+ * @param int|null $itemId
+ * @return void
*/
public function testAfterSave(
- $appliedTaxes,
- $itemAppliedTaxes,
- $expectedTaxes,
- $expectedItemTaxes
- ) {
+ array $appliedTaxes,
+ array $itemAppliedTaxes,
+ array $expectedTaxes,
+ array $expectedItemTaxes,
+ ?int $itemId
+ ): void {
$orderMock = $this->setupOrderMock();
$extensionAttributeMock = $this->setupExtensionAttributeMock();
- $extensionAttributeMock->expects($this->any())
- ->method('getConvertingFromQuote')
+ $extensionAttributeMock->method('getConvertingFromQuote')
->willReturn(true);
- $extensionAttributeMock->expects($this->any())
- ->method('getAppliedTaxes')
+ $extensionAttributeMock->method('getAppliedTaxes')
->willReturn($appliedTaxes);
- $extensionAttributeMock->expects($this->any())
- ->method('getItemAppliedTaxes')
+ $extensionAttributeMock->method('getItemAppliedTaxes')
->willReturn($itemAppliedTaxes);
$orderItemMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Item::class)
->disableOriginalConstructor()
->setMethods(['getId'])
->getMock();
- $orderItemMock->expects($this->atLeastOnce())
- ->method('getId')
- ->willReturn(self::ORDER_ITEM_ID);
- $orderMock->expects($this->once())
- ->method('getAppliedTaxIsSaved')
+ $orderItemMock->method('getId')
+ ->willReturn($itemId);
+ $orderMock->method('getAppliedTaxIsSaved')
->willReturn(false);
- $orderMock->expects($this->once())
- ->method('getExtensionAttributes')
+ $orderMock->method('getExtensionAttributes')
->willReturn($extensionAttributeMock);
- $orderMock->expects($this->atLeastOnce())
- ->method('getItemByQuoteItemId')
+ $itemByQuoteId = $itemId ? $orderItemMock : $itemId;
+ $orderMock->method('getItemByQuoteItemId')
->with(self::ITEMID)
- ->willReturn($orderItemMock);
- $orderMock->expects($this->atLeastOnce())
- ->method('getEntityId')
+ ->willReturn($itemByQuoteId);
+ $orderMock->method('getEntityId')
->willReturn(self::ORDERID);
- $orderMock->expects($this->once())
- ->method('setAppliedTaxIsSaved')
+ $orderMock->method('setAppliedTaxIsSaved')
->with(true);
$this->verifyOrderTaxes($expectedTaxes);
@@ -228,10 +229,12 @@ public function testAfterSave(
}
/**
+ * After save data provider
+ *
* @return array
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
- public function afterSaveDataProvider()
+ public function afterSaveDataProvider(): array
{
return [
//one item with shipping
@@ -485,6 +488,257 @@ public function afterSaveDataProvider()
'taxable_item_type' => 'shipping',
],
],
+ 'item_id' => self::ORDER_ITEM_ID,
+ ],
+ 'associated_item_with_empty_order_quote_item' => [
+ 'applied_taxes' => [
+ [
+ 'amount' => 0.66,
+ 'base_amount' => 0.66,
+ 'percent' => 11,
+ 'id' => 'ILUS',
+ 'extension_attributes' => [
+ 'rates' => [
+ [
+ 'percent' => 6,
+ 'code' => 'IL',
+ 'title' => 'IL',
+ ],
+ [
+ 'percent' => 5,
+ 'code' => 'US',
+ 'title' => 'US',
+ ],
+ ]
+ ],
+ ],
+ [
+ 'amount' => 0.2,
+ 'base_amount' => 0.2,
+ 'percent' => 3.33,
+ 'id' => 'CityTax',
+ 'extension_attributes' => [
+ 'rates' => [
+ [
+ 'percent' => 3,
+ 'code' => 'CityTax',
+ 'title' => 'CityTax',
+ ],
+ ]
+ ],
+ ],
+ ],
+ 'item_applied_taxes' => [
+ //item tax, three tax rates
+ [
+ //first two taxes are combined
+ 'item_id' => null,
+ 'type' => 'product',
+ 'associated_item_id' => self::ITEMID,
+ 'applied_taxes' => [
+ [
+ 'amount' => 0.11,
+ 'base_amount' => 0.11,
+ 'percent' => 11,
+ 'id' => 'ILUS',
+ 'extension_attributes' => [
+ 'rates' => [
+ [
+ 'percent' => 6,
+ 'code' => 'IL',
+ 'title' => 'IL',
+ ],
+ [
+ 'percent' => 5,
+ 'code' => 'US',
+ 'title' => 'US',
+ ],
+ ]
+ ],
+ ],
+ //city tax
+ [
+ 'amount' => 0.03,
+ 'base_amount' => 0.03,
+ 'percent' => 3.33,
+ 'id' => 'CityTax',
+ 'extension_attributes' => [
+ 'rates' => [
+ [
+ 'percent' => 3,
+ 'code' => 'CityTax',
+ 'title' => 'CityTax',
+ ],
+ ]
+ ],
+ ],
+ ],
+ ],
+ //shipping tax
+ [
+ //first two taxes are combined
+ 'item_id' => null,
+ 'type' => 'shipping',
+ 'associated_item_id' => null,
+ 'applied_taxes' => [
+ [
+ 'amount' => 0.55,
+ 'base_amount' => 0.55,
+ 'percent' => 11,
+ 'id' => 'ILUS',
+ 'extension_attributes' => [
+ 'rates' => [
+ [
+ 'percent' => 6,
+ 'code' => 'IL',
+ 'title' => 'IL',
+ ],
+ [
+ 'percent' => 5,
+ 'code' => 'US',
+ 'title' => 'US',
+ ],
+ ]
+ ],
+ ],
+ //city tax
+ [
+ 'amount' => 0.17,
+ 'base_amount' => 0.17,
+ 'percent' => 3.33,
+ 'id' => 'CityTax',
+ 'extension_attributes' => [
+ 'rates' => [
+ [
+ 'percent' => 3,
+ 'code' => 'CityTax',
+ 'title' => 'CityTax',
+ ],
+ ]
+ ],
+ ],
+ ],
+ ],
+ ],
+ 'expected_order_taxes' => [
+ //state tax
+ '35' => [
+ 'order_id' => self::ORDERID,
+ 'code' => 'IL',
+ 'title' => 'IL',
+ 'hidden' => 0,
+ 'percent' => 6,
+ 'priority' => 0,
+ 'position' => 0,
+ 'amount' => 0.66,
+ 'base_amount' => 0.66,
+ 'process' => 0,
+ 'base_real_amount' => 0.36,
+ ],
+ //federal tax
+ '36' => [
+ 'order_id' => self::ORDERID,
+ 'code' => 'US',
+ 'title' => 'US',
+ 'hidden' => 0,
+ 'percent' => 5,
+ 'priority' => 0,
+ 'position' => 0,
+ 'amount' => 0.66, //combined amount
+ 'base_amount' => 0.66,
+ 'process' => 0,
+ 'base_real_amount' => 0.3, //portion for specific rate
+ ],
+ //city tax
+ '37' => [
+ 'order_id' => self::ORDERID,
+ 'code' => 'CityTax',
+ 'title' => 'CityTax',
+ 'hidden' => 0,
+ 'percent' => 3,
+ 'priority' => 0,
+ 'position' => 0,
+ 'amount' => 0.2, //combined amount
+ 'base_amount' => 0.2,
+ 'process' => 0,
+ 'base_real_amount' => 0.18018018018018, //this number is meaningless since this is single rate
+ ],
+ ],
+ 'expected_item_taxes' => [
+ [
+ //state tax for item
+ 'item_id' => null,
+ 'tax_id' => '35',
+ 'tax_percent' => 6,
+ 'associated_item_id' => null,
+ 'amount' => 0.11,
+ 'base_amount' => 0.11,
+ 'real_amount' => 0.06,
+ 'real_base_amount' => 0.06,
+ 'taxable_item_type' => 'product',
+ ],
+ [
+ //state tax for shipping
+ 'item_id' => null,
+ 'tax_id' => '35',
+ 'tax_percent' => 6,
+ 'associated_item_id' => null,
+ 'amount' => 0.55,
+ 'base_amount' => 0.55,
+ 'real_amount' => 0.3,
+ 'real_base_amount' => 0.3,
+ 'taxable_item_type' => 'shipping',
+ ],
+ [
+ //federal tax for item
+ 'item_id' => null,
+ 'tax_id' => '36',
+ 'tax_percent' => 5,
+ 'associated_item_id' => null,
+ 'amount' => 0.11,
+ 'base_amount' => 0.11,
+ 'real_amount' => 0.05,
+ 'real_base_amount' => 0.05,
+ 'taxable_item_type' => 'product',
+ ],
+ [
+ //federal tax for shipping
+ 'item_id' => null,
+ 'tax_id' => '36',
+ 'tax_percent' => 5,
+ 'associated_item_id' => null,
+ 'amount' => 0.55,
+ 'base_amount' => 0.55,
+ 'real_amount' => 0.25,
+ 'real_base_amount' => 0.25,
+ 'taxable_item_type' => 'shipping',
+ ],
+ [
+ //city tax for item
+ 'item_id' => null,
+ 'tax_id' => '37',
+ 'tax_percent' => 3.33,
+ 'associated_item_id' => null,
+ 'amount' => 0.03,
+ 'base_amount' => 0.03,
+ 'real_amount' => 0.03,
+ 'real_base_amount' => 0.03,
+ 'taxable_item_type' => 'product',
+ ],
+ [
+ //city tax for shipping
+ 'item_id' => null,
+ 'tax_id' => '37',
+ 'tax_percent' => 3.33,
+ 'associated_item_id' => null,
+ 'amount' => 0.17,
+ 'base_amount' => 0.17,
+ 'real_amount' => 0.17,
+ 'real_base_amount' => 0.17,
+ 'taxable_item_type' => 'shipping',
+ ],
+ ],
+ 'item_id' => null,
],
];
}
diff --git a/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php b/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php
index e528f9e88d8a4..c998c02d46b3c 100644
--- a/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php
+++ b/app/code/Magento/Theme/Model/PageLayout/Config/Builder.php
@@ -94,17 +94,17 @@ public function getPageLayoutsConfig()
protected function getConfigFiles()
{
if (!$this->configFiles) {
- $configFiles = [];
$this->configFiles = $this->cacheModel->load(self::CACHE_KEY_LAYOUTS);
if (!empty($this->configFiles)) {
//if value in cache is corrupted.
$this->configFiles = $this->serializer->unserialize($this->configFiles);
}
if (empty($this->configFiles)) {
+ $configFiles = [];
foreach ($this->themeCollection->loadRegisteredThemes() as $theme) {
$configFiles[] = $this->fileCollector->getFilesContent($theme, 'layouts.xml');
}
- $this->configFiles = array_merge(...$configFiles);
+ $this->configFiles = array_merge([], ...$configFiles);
$this->cacheModel->save($this->serializer->serialize($this->configFiles), self::CACHE_KEY_LAYOUTS);
}
}
diff --git a/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php b/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php
index ef2df77e7daff..3600992011ed6 100644
--- a/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php
+++ b/app/code/Magento/Ui/Component/Form/Element/DataType/Date.php
@@ -111,7 +111,7 @@ public function getComponentName()
public function convertDate($date, $hour = 0, $minute = 0, $second = 0, $setUtcTimeZone = true)
{
try {
- $dateObj = $this->localeDate->date($date, $this->getLocale(), false);
+ $dateObj = $this->localeDate->date($date, $this->getLocale(), false, false);
$dateObj->setTime($hour, $minute, $second);
//convert store date to default date in UTC timezone without DST
if ($setUtcTimeZone) {
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
index 73bef62910644..e7dc245d47d6f 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
@@ -54,13 +54,14 @@ define([
this.$fileInput = fileInput;
_.extend(this.uploaderConfig, {
- dropZone: $(fileInput).closest(this.dropZone),
- change: this.onFilesChoosed.bind(this),
- drop: this.onFilesChoosed.bind(this),
- add: this.onBeforeFileUpload.bind(this),
- done: this.onFileUploaded.bind(this),
- start: this.onLoadingStart.bind(this),
- stop: this.onLoadingStop.bind(this)
+ dropZone: $(fileInput).closest(this.dropZone),
+ change: this.onFilesChoosed.bind(this),
+ drop: this.onFilesChoosed.bind(this),
+ add: this.onBeforeFileUpload.bind(this),
+ fail: this.onFail.bind(this),
+ done: this.onFileUploaded.bind(this),
+ start: this.onLoadingStart.bind(this),
+ stop: this.onLoadingStop.bind(this)
});
$(fileInput).fileupload(this.uploaderConfig);
@@ -328,11 +329,12 @@ define([
* May be used for implementation of additional validation rules,
* e.g. total files and a total size rules.
*
- * @param {Event} e - Event object.
+ * @param {Event} event - Event object.
* @param {Object} data - File data that will be uploaded.
*/
- onFilesChoosed: function (e, data) {
- // no option exists in fileuploader for restricting upload chains to single files; this enforces that policy
+ onFilesChoosed: function (event, data) {
+ // no option exists in file uploader for restricting upload chains to single files
+ // this enforces that policy
if (!this.isMultipleFiles) {
data.files.splice(1);
}
@@ -341,13 +343,13 @@ define([
/**
* Handler which is invoked prior to the start of a file upload.
*
- * @param {Event} e - Event object.
+ * @param {Event} event - Event object.
* @param {Object} data - File data that will be uploaded.
*/
- onBeforeFileUpload: function (e, data) {
- var file = data.files[0],
- allowed = this.isFileAllowed(file),
- target = $(e.target);
+ onBeforeFileUpload: function (event, data) {
+ var file = data.files[0],
+ allowed = this.isFileAllowed(file),
+ target = $(event.target);
if (this.disabled()) {
this.notifyError($t('The file upload field is disabled.'));
@@ -356,7 +358,7 @@ define([
}
if (allowed.passed) {
- target.on('fileuploadsend', function (event, postData) {
+ target.on('fileuploadsend', function (eventBound, postData) {
postData.data.append('param_name', this.paramName);
}.bind(data));
@@ -386,16 +388,25 @@ define([
});
},
+ /**
+ * @param {Event} event
+ * @param {Object} data
+ */
+ onFail: function (event, data) {
+ console.error(data.jqXHR.responseText);
+ console.error(data.jqXHR.status);
+ },
+
/**
* Handler of the file upload complete event.
*
- * @param {Event} e
+ * @param {Event} event
* @param {Object} data
*/
- onFileUploaded: function (e, data) {
+ onFileUploaded: function (event, data) {
var uploadedFilename = data.files[0].name,
- file = data.result,
- error = file.error;
+ file = data.result,
+ error = file.error;
error ?
this.aggregateError(uploadedFilename, error) :
@@ -469,10 +480,10 @@ define([
* Handler of the preview image load event.
*
* @param {Object} file - File associated with an image.
- * @param {Event} e
+ * @param {Event} event
*/
- onPreviewLoad: function (file, e) {
- var img = e.currentTarget;
+ onPreviewLoad: function (file, event) {
+ var img = event.currentTarget;
file.previewWidth = img.naturalWidth;
file.previewHeight = img.naturalHeight;
diff --git a/app/code/Magento/Ups/Model/Carrier.php b/app/code/Magento/Ups/Model/Carrier.php
index b6e539bdadcb9..4d0e3efee35aa 100644
--- a/app/code/Magento/Ups/Model/Carrier.php
+++ b/app/code/Magento/Ups/Model/Carrier.php
@@ -1135,7 +1135,7 @@ protected function _getXmlTracking($trackings)
XMLAuth;
- $trackingResponses[] = $this->asyncHttpClient->request(
+ $trackingResponses[$tracking] = $this->asyncHttpClient->request(
new Request(
$url,
Request::METHOD_POST,
@@ -1144,13 +1144,9 @@ protected function _getXmlTracking($trackings)
)
);
}
- foreach ($trackingResponses as $response) {
+ foreach ($trackingResponses as $tracking => $response) {
$httpResponse = $response->get();
- if ($httpResponse->getStatusCode() >= 400) {
- $xmlResponse = '';
- } else {
- $xmlResponse = $httpResponse->getBody();
- }
+ $xmlResponse = $httpResponse->getStatusCode() >= 400 ? '' : $httpResponse->getBody();
$this->_parseXmlTrackingResponse($tracking, $xmlResponse);
}
@@ -1362,10 +1358,11 @@ public function getAllowedMethods()
protected function _formShipmentRequest(DataObject $request)
{
$packages = $request->getPackages();
+ $shipmentItems = [];
foreach ($packages as $package) {
$shipmentItems[] = $package['items'];
}
- $shipmentItems = array_merge(...$shipmentItems);
+ $shipmentItems = array_merge([], ...$shipmentItems);
$xmlRequest = $this->_xmlElFactory->create(
['data' => '']
@@ -1528,24 +1525,18 @@ protected function _formShipmentRequest(DataObject $request)
}
if ($deliveryConfirmation && $deliveryConfirmationLevel === self::DELIVERY_CONFIRMATION_PACKAGE) {
- $serviceOptionsNode = $packagePart[$packageId]->addChild('PackageServiceOptions');
- $serviceOptionsNode->addChild(
- 'DeliveryConfirmation'
- )->addChild(
- 'DCISType',
- $deliveryConfirmation
- );
+ $serviceOptionsNode = $packagePart[$packageId]->addChild('PackageServiceOptions');
+ $serviceOptionsNode
+ ->addChild('DeliveryConfirmation')
+ ->addChild('DCISType', $deliveryConfirmation);
}
}
if (isset($deliveryConfirmation) && $deliveryConfirmationLevel === self::DELIVERY_CONFIRMATION_SHIPMENT) {
$serviceOptionsNode = $shipmentPart->addChild('ShipmentServiceOptions');
- $serviceOptionsNode->addChild(
- 'DeliveryConfirmation'
- )->addChild(
- 'DCISType',
- $deliveryConfirmation
- );
+ $serviceOptionsNode
+ ->addChild('DeliveryConfirmation')
+ ->addChild('DCISType', $deliveryConfirmation);
}
$shipmentPart->addChild('PaymentInformation')
@@ -1627,6 +1618,7 @@ protected function _sendShipmentAcceptRequest(Element $shipmentConfirmResponse)
try {
$response = $this->_xmlElFactory->create(['data' => $xmlResponse]);
} catch (Throwable $e) {
+ $response = $this->_xmlElFactory->create(['data' => '']);
$debugData['result'] = ['error' => $e->getMessage(), 'code' => $e->getCode()];
}
@@ -1800,6 +1792,7 @@ protected function _doShipmentRequest(DataObject $request)
$this->setXMLAccessRequest();
$xmlRequest = $this->_xmlAccessRequest . $rawXmlRequest;
$xmlResponse = $this->_getCachedQuotes($xmlRequest);
+ $debugData = [];
if ($xmlResponse === null) {
$debugData['request'] = $this->filterDebugData($this->_xmlAccessRequest) . $rawXmlRequest;
diff --git a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php
index e6b03755bea47..6430f71765fe4 100644
--- a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php
+++ b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php
@@ -64,7 +64,9 @@ public function resolve(
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
$result = null;
- $url = $args['url'];
+ // phpcs:ignore Magento2.Functions.DiscouragedFunction
+ $urlParts = parse_url($args['url']);
+ $url = $urlParts['path'] ?? $args['url'];
if (substr($url, 0, 1) === '/' && $url !== '/') {
$url = ltrim($url, '/');
}
@@ -81,6 +83,9 @@ public function resolve(
'redirectCode' => $this->redirectType,
'type' => $this->sanitizeType($finalUrlRewrite->getEntityType())
];
+ if (!empty($urlParts['query'])) {
+ $resultArray['relative_url'] .= '?' . $urlParts['query'];
+ }
if (empty($resultArray['id'])) {
throw new GraphQlNoSuchEntityException(
diff --git a/app/code/Magento/User/Test/Mftf/Section/AdminDeleteRoleSection.xml b/app/code/Magento/User/Test/Mftf/Section/AdminDeleteRoleSection.xml
deleted file mode 100644
index 6a0d0c9210396..0000000000000
--- a/app/code/Magento/User/Test/Mftf/Section/AdminDeleteRoleSection.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/code/Magento/User/Test/Mftf/Section/AdminDeleteUserSection.xml b/app/code/Magento/User/Test/Mftf/Section/AdminDeleteUserSection.xml
deleted file mode 100644
index 21ca1cb36f988..0000000000000
--- a/app/code/Magento/User/Test/Mftf/Section/AdminDeleteUserSection.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
diff --git a/app/code/Magento/User/Test/Mftf/Section/AdminRoleGridSection/AdminDeleteRoleSection.xml b/app/code/Magento/User/Test/Mftf/Section/AdminRoleGridSection/AdminDeleteRoleSection.xml
index e369d037d28f6..dba7dd4cd520c 100644
--- a/app/code/Magento/User/Test/Mftf/Section/AdminRoleGridSection/AdminDeleteRoleSection.xml
+++ b/app/code/Magento/User/Test/Mftf/Section/AdminRoleGridSection/AdminDeleteRoleSection.xml
@@ -9,7 +9,8 @@
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
-
+
+
diff --git a/app/code/Magento/User/Test/Mftf/Section/AdminUserGridSection/AdminDeleteUserSection.xml b/app/code/Magento/User/Test/Mftf/Section/AdminUserGridSection/AdminDeleteUserSection.xml
index d4718ca43d6cf..3937ee75c6b7d 100644
--- a/app/code/Magento/User/Test/Mftf/Section/AdminUserGridSection/AdminDeleteUserSection.xml
+++ b/app/code/Magento/User/Test/Mftf/Section/AdminUserGridSection/AdminDeleteUserSection.xml
@@ -11,7 +11,7 @@
-
+
diff --git a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php
index f38c0f0978536..5ead1beb722dd 100644
--- a/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php
+++ b/app/code/Magento/Webapi/Model/Rest/Swagger/Generator.php
@@ -33,10 +33,8 @@ class Generator extends AbstractSchemaGenerator
*/
const ERROR_SCHEMA = '#/definitions/error-response';
- /** Unauthorized description */
const UNAUTHORIZED_DESCRIPTION = '401 Unauthorized';
- /** Array signifier */
const ARRAY_SIGNIFIER = '[0]';
/**
@@ -758,7 +756,7 @@ private function handleComplex($name, $type, $prefix, $isArray)
);
}
- return empty($queryNames) ? [] : array_merge(...$queryNames);
+ return array_merge([], ...$queryNames);
}
/**
diff --git a/app/code/Magento/Weee/Model/Total/Quote/Weee.php b/app/code/Magento/Weee/Model/Total/Quote/Weee.php
index 449c6cd688668..e7ae84c15a51f 100644
--- a/app/code/Magento/Weee/Model/Total/Quote/Weee.php
+++ b/app/code/Magento/Weee/Model/Total/Quote/Weee.php
@@ -306,12 +306,12 @@ protected function getNextIncrement()
*/
protected function recalculateParent(AbstractItem $item)
{
- $associatedTaxables = [[]];
+ $associatedTaxables = [];
foreach ($item->getChildren() as $child) {
$associatedTaxables[] = $child->getAssociatedTaxables();
}
$item->setAssociatedTaxables(
- array_unique(array_merge(...$associatedTaxables))
+ array_unique(array_merge([], ...$associatedTaxables))
);
}
diff --git a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml
index 6dab476115cee..a3af1dd95e70c 100644
--- a/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml
+++ b/app/code/Magento/Widget/view/adminhtml/templates/instance/edit/layout.phtml
@@ -5,11 +5,12 @@
*/
/** @var \Magento\Widget\Block\Adminhtml\Widget\Instance\Edit\Tab\Main\Layout $block */
+/** @var \Magento\Framework\Escaper $escaper */
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
?>