From aa12503923ac994873724ecaa759e1eb14b318dc Mon Sep 17 00:00:00 2001 From: Jason Woods Date: Wed, 8 Jul 2020 10:44:26 +0100 Subject: [PATCH 001/346] Add warning to deadlock cron retrier to log any future failures for investigation Change key for cron_schedule to cover all queries currently run, ensuring range is on the end of the key Refactor cron locking to remove UPDATE+JOIN which causes shared locks on the join followed by exclusive locks for the update, which can deadlock, to instead use an explicit full exclusive lock on all entries using forUpdate Implement cleanup of jobs that were running but did not complete and did not error, which can occur if PHP crashes or is killed, or database is restored from backup or migrated to staging environments --- .../Magento/Cron/Model/DeadlockRetrier.php | 15 ++++++++ .../Cron/Model/ResourceModel/Schedule.php | 36 +++++++++++++------ .../Observer/ProcessCronQueueObserver.php | 30 ++++++++++++++++ .../Test/Unit/Model/DeadlockRetrierTest.php | 13 ++++++- .../Observer/ProcessCronQueueObserverTest.php | 26 +++++++++++--- app/code/Magento/Cron/etc/db_schema.xml | 6 ++-- 6 files changed, 107 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/Cron/Model/DeadlockRetrier.php b/app/code/Magento/Cron/Model/DeadlockRetrier.php index 15497910a089b..63f7453c8df3c 100644 --- a/app/code/Magento/Cron/Model/DeadlockRetrier.php +++ b/app/code/Magento/Cron/Model/DeadlockRetrier.php @@ -17,6 +17,20 @@ */ class DeadlockRetrier implements DeadlockRetrierInterface { + /** + * @var \Psr\Log\LoggerInterface + */ + private $logger; + + /** + * @param \Psr\Log\LoggerInterface $logger + */ + public function __construct( + \Psr\Log\LoggerInterface $logger + ) { + $this->logger = $logger; + } + /** * @inheritdoc */ @@ -30,6 +44,7 @@ public function execute(callable $callback, AdapterInterface $connection) try { return $callback(); } catch (DeadlockException $e) { + $this->logger->warning(sprintf("Deadlock detected in cron cleanup: %s", $e->getMessage())); continue; } } diff --git a/app/code/Magento/Cron/Model/ResourceModel/Schedule.php b/app/code/Magento/Cron/Model/ResourceModel/Schedule.php index 25ebaec5582c9..120e0ce6432c5 100644 --- a/app/code/Magento/Cron/Model/ResourceModel/Schedule.php +++ b/app/code/Magento/Cron/Model/ResourceModel/Schedule.php @@ -65,31 +65,47 @@ public function trySetJobStatusAtomic($scheduleId, $newStatus, $currentStatus) public function trySetJobUniqueStatusAtomic($scheduleId, $newStatus, $currentStatus) { $connection = $this->getConnection(); + $connection->beginTransaction(); // this condition added to avoid cron jobs locking after incorrect termination of running job $match = $connection->quoteInto( 'existing.job_code = current.job_code ' . - 'AND (existing.executed_at > UTC_TIMESTAMP() - INTERVAL 1 DAY OR existing.executed_at IS NULL) ' . - 'AND existing.status = ?', + 'AND existing.status = ? ' . + 'AND (existing.executed_at > UTC_TIMESTAMP() - INTERVAL 1 DAY OR existing.executed_at IS NULL)', $newStatus ); + // Select and lock all related schedules - this prevents deadlock in case cron overlaps and two jobs of + // the same code attempt to lock at the same time, and force them to serialize $selectIfUnlocked = $connection->select() + ->from( + ['current' => $this->getTable('cron_schedule')], + [] + ) ->joinLeft( ['existing' => $this->getTable('cron_schedule')], $match, - ['status' => new \Zend_Db_Expr($connection->quote($newStatus))] + ['existing.schedule_id'] ) ->where('current.schedule_id = ?', $scheduleId) ->where('current.status = ?', $currentStatus) - ->where('existing.schedule_id IS NULL'); - - $update = $connection->updateFromSelect($selectIfUnlocked, ['current' => $this->getTable('cron_schedule')]); - $result = $connection->query($update)->rowCount(); + ->forUpdate(true); - if ($result == 1) { - return true; + $scheduleId = $connection->fetchOne($selectIfUnlocked); + if (!empty($scheduleId)) { + // Existing running schedule found + $connection->commit(); + return false; } - return false; + + // Mark our schedule as running + $connection->update( + $this->getTable('cron_schedule'), + ['status' => new \Zend_Db_Expr($connection->quote($newStatus))], + ['schedule_id = ?' => $scheduleId] + ); + + $connection->commit(); + return true; } } diff --git a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php index acffba02eb461..a6a8f77c039d8 100644 --- a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php +++ b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php @@ -550,6 +550,7 @@ private function cleanupJobs($groupId, $currentTime) ); $this->cleanupDisabledJobs($groupId); + $this->cleanupRunningJobs($groupId); $historySuccess = (int)$this->getCronGroupConfigurationValue($groupId, self::XML_PATH_HISTORY_SUCCESS); $historyFailure = (int)$this->getCronGroupConfigurationValue($groupId, self::XML_PATH_HISTORY_FAILURE); @@ -696,6 +697,35 @@ private function cleanupDisabledJobs($groupId) } } + /** + * Cleanup jobs that were left in a running state due to an unexpected stop + * + * @param string $groupId + * @return void + */ + private function cleanupRunningJobs($groupId) + { + $scheduleResource = $this->_scheduleFactory->create()->getResource(); + $connection = $scheduleResource->getConnection(); + + $jobs = $this->_config->getJobs(); + + $connection->update( + $scheduleResource->getMainTable(), + [ + 'status' => \Magento\Cron\Model\Schedule::STATUS_ERROR, + 'messages' => 'Time out' + ], + $connection->quoteInto( + 'status = ? ' . + 'AND job_code IN (?) ' . + 'AND (scheduled_at < UTC_TIMESTAMP() - INTERVAL 1 DAY)', + \Magento\Cron\Model\Schedule::STATUS_RUNNING, + array_keys($jobs[$groupId]) + ) + ); + } + /** * Get cron expression of cron job. * diff --git a/app/code/Magento/Cron/Test/Unit/Model/DeadlockRetrierTest.php b/app/code/Magento/Cron/Test/Unit/Model/DeadlockRetrierTest.php index 60eaa091a761f..36e4537383aa6 100644 --- a/app/code/Magento/Cron/Test/Unit/Model/DeadlockRetrierTest.php +++ b/app/code/Magento/Cron/Test/Unit/Model/DeadlockRetrierTest.php @@ -13,6 +13,7 @@ use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Adapter\DeadlockException; use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; class DeadlockRetrierTest extends \PHPUnit\Framework\TestCase { @@ -27,6 +28,11 @@ class DeadlockRetrierTest extends \PHPUnit\Framework\TestCase */ private $adapterMock; + /** + * @var LoggerInterface|MockObject + */ + private $loggerMock; + /** * @var AbstractModel|MockObject */ @@ -38,8 +44,9 @@ class DeadlockRetrierTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { $this->adapterMock = $this->getMockForAbstractClass(AdapterInterface::class); + $this->loggerMock = $this->getMockForAbstractClass(LoggerInterface::class); $this->modelMock = $this->createMock(AbstractModel::class); - $this->retrier = new DeadlockRetrier(); + $this->retrier = new DeadlockRetrier($this->loggerMock); } /** @@ -75,6 +82,8 @@ public function testRetry(): void $this->modelMock->expects($this->exactly(DeadlockRetrierInterface::MAX_RETRIES)) ->method('getId') ->willThrowException(new DeadlockException()); + $this->loggerMock->expects($this->exactly(DeadlockRetrierInterface::MAX_RETRIES - 1)) + ->method('warning'); $this->retrier->execute( function () { @@ -95,6 +104,8 @@ public function testRetrySecond(): void $this->modelMock->expects($this->at(1)) ->method('getId') ->willReturn(2); + $this->loggerMock->expects($this->once()) + ->method('warning'); $this->retrier->execute( function () { diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index e1e28ff6f06a3..9414680ce0e45 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -1047,8 +1047,8 @@ public function testMissedJobsCleanedInTime() $this->scheduleCollectionMock->expects($this->any())->method('load')->willReturnSelf(); $scheduleMock->expects($this->any())->method('getCollection')->willReturn($this->scheduleCollectionMock); - $scheduleMock->expects($this->exactly(9))->method('getResource')->willReturn($this->scheduleResourceMock); - $this->scheduleFactoryMock->expects($this->exactly(10))->method('create')->willReturn($scheduleMock); + $scheduleMock->expects($this->exactly(10))->method('getResource')->willReturn($this->scheduleResourceMock); + $this->scheduleFactoryMock->expects($this->exactly(11))->method('create')->willReturn($scheduleMock); $connectionMock = $this->getMockForAbstractClass(AdapterInterface::class); @@ -1078,11 +1078,29 @@ public function testMissedJobsCleanedInTime() ) ->willReturn(1); - $this->scheduleResourceMock->expects($this->exactly(5)) + $connectionMock->expects($this->once()) + ->method('quoteInto') + ->with( + 'status = ? AND job_code IN (?) AND (scheduled_at < UTC_TIMESTAMP() - INTERVAL 1 DAY)', + ['test_job1'], + 'running' + ) + ->willReturn(''); + + $connectionMock->expects($this->once()) + ->method('update') + ->with( + $tableName, + ['status' => 'error', 'messages' => 'Time out'], + '' + ) + ->willReturn(0); + + $this->scheduleResourceMock->expects($this->exactly(6)) ->method('getTable') ->with($tableName) ->willReturn($tableName); - $this->scheduleResourceMock->expects($this->exactly(14)) + $this->scheduleResourceMock->expects($this->exactly(15)) ->method('getConnection') ->willReturn($connectionMock); diff --git a/app/code/Magento/Cron/etc/db_schema.xml b/app/code/Magento/Cron/etc/db_schema.xml index f26b6feea3b3b..527cdbcc5fb86 100644 --- a/app/code/Magento/Cron/etc/db_schema.xml +++ b/app/code/Magento/Cron/etc/db_schema.xml @@ -21,12 +21,10 @@ - + + - - - From b0b72b0f8486ca119015e84b7786dfab13d2e475 Mon Sep 17 00:00:00 2001 From: Jason Woods Date: Thu, 16 Jul 2020 14:53:52 +0100 Subject: [PATCH 002/346] Higher cardinality first after tested shown still no deadlocks --- app/code/Magento/Cron/etc/db_schema.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Cron/etc/db_schema.xml b/app/code/Magento/Cron/etc/db_schema.xml index 527cdbcc5fb86..72b1428756898 100644 --- a/app/code/Magento/Cron/etc/db_schema.xml +++ b/app/code/Magento/Cron/etc/db_schema.xml @@ -21,9 +21,9 @@ - - + + From 96029b55f7cd00b58967637aedac67ddd1767bad Mon Sep 17 00:00:00 2001 From: Jason Woods Date: Fri, 21 Aug 2020 10:37:47 +0100 Subject: [PATCH 003/346] Fix test --- .../Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index 9414680ce0e45..98ec3c918f539 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -1082,8 +1082,8 @@ public function testMissedJobsCleanedInTime() ->method('quoteInto') ->with( 'status = ? AND job_code IN (?) AND (scheduled_at < UTC_TIMESTAMP() - INTERVAL 1 DAY)', - ['test_job1'], - 'running' + 'running', + ['test_job1'] ) ->willReturn(''); From 68d679b7bd7d371c5266d4803f03f204893f7af2 Mon Sep 17 00:00:00 2001 From: Jason Woods Date: Fri, 21 Aug 2020 12:04:43 +0100 Subject: [PATCH 004/346] Reduce line count to fix static testing --- .../Observer/ProcessCronQueueObserverTest.php | 40 +++++-------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index 98ec3c918f539..816fdb6173d8b 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -764,22 +764,17 @@ function ($callback) { ->method('getCollection')->willReturn($this->scheduleCollectionMock); $scheduleMock->expects($this->any()) ->method('getResource')->willReturn($this->scheduleResourceMock); - $this->scheduleFactoryMock->expects($this->once(2)) + $this->scheduleFactoryMock->expects($this->once()) ->method('create')->willReturn($scheduleMock); $testCronJob = $this->getMockBuilder('CronJob') ->setMethods(['execute'])->getMock(); $testCronJob->expects($this->atLeastOnce())->method('execute')->with($schedule); - $this->objectManagerMock->expects( - $this->once() - )->method( - 'create' - )->with( - 'CronJob' - )->willReturn( - $testCronJob - ); + $this->objectManagerMock->expects($this->once()) + ->method('create') + ->with('CronJob') + ->willReturn($testCronJob); $this->cronQueueObserver->execute($this->observerMock); } @@ -1055,26 +1050,11 @@ public function testMissedJobsCleanedInTime() $connectionMock->expects($this->exactly(5)) ->method('delete') ->withConsecutive( - [ - $tableName, - ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1']] - ], - [ - $tableName, - ['status = ?' => 'success', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] - ], - [ - $tableName, - ['status = ?' => 'missed', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] - ], - [ - $tableName, - ['status = ?' => 'error', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] - ], - [ - $tableName, - ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] - ] + [$tableName, ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1']]], + [$tableName, ['status = ?' => 'success', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]], + [$tableName, ['status = ?' => 'missed', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]], + [$tableName, ['status = ?' => 'error', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]], + [$tableName, ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]] ) ->willReturn(1); From a90161907aedae371cb307759b685cc254efe2d8 Mon Sep 17 00:00:00 2001 From: Jason Woods Date: Fri, 21 Aug 2020 13:10:43 +0100 Subject: [PATCH 005/346] Fix test failure due to table fetch --- app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php index a6a8f77c039d8..de42027742c6e 100644 --- a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php +++ b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php @@ -711,7 +711,7 @@ private function cleanupRunningJobs($groupId) $jobs = $this->_config->getJobs(); $connection->update( - $scheduleResource->getMainTable(), + $scheduleResource->getTable('cron_schedule'), [ 'status' => \Magento\Cron\Model\Schedule::STATUS_ERROR, 'messages' => 'Time out' From dda5c72c9303f9476ce7041743c87079cada87f6 Mon Sep 17 00:00:00 2001 From: Ihor Sviziev Date: Tue, 25 Aug 2020 13:40:25 +0300 Subject: [PATCH 006/346] Cron cleanup repeatedly hits deadlocks on large environments Fix failing tests --- .../Observer/ProcessCronQueueObserver.php | 47 +++++----- .../Observer/ProcessCronQueueObserverTest.php | 90 +++++++++++++------ .../Magento/Cron/etc/db_schema_whitelist.json | 5 +- 3 files changed, 87 insertions(+), 55 deletions(-) diff --git a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php index de42027742c6e..0f266b5d62d83 100644 --- a/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php +++ b/app/code/Magento/Cron/Observer/ProcessCronQueueObserver.php @@ -9,6 +9,7 @@ */ namespace Magento\Cron\Observer; +use Magento\Cron\Model\ResourceModel\Schedule\Collection as ScheduleCollection; use Magento\Cron\Model\Schedule; use Magento\Framework\App\State; use Magento\Framework\Console\Cli; @@ -83,7 +84,7 @@ class ProcessCronQueueObserver implements ObserverInterface const MAX_RETRIES = 5; /** - * @var \Magento\Cron\Model\ResourceModel\Schedule\Collection + * @var ScheduleCollection */ protected $_pendingSchedules; @@ -278,12 +279,12 @@ function ($groupId) use ($currentTime) { * * It should be taken by standalone (child) process, not by the parent process. * - * @param int $groupId + * @param string $groupId * @param callable $callback * * @return void */ - private function lockGroup($groupId, callable $callback) + private function lockGroup(string $groupId, callable $callback): void { if (!$this->lockManager->lock(self::LOCK_PREFIX . $groupId, self::LOCK_TIMEOUT)) { $this->logger->warning( @@ -399,7 +400,7 @@ function () use ($schedule) { * @param string $jobName * @return void */ - private function startProfiling(string $jobName = '') + private function startProfiling(string $jobName = ''): void { $this->statProfiler->clear(); $this->statProfiler->start( @@ -416,7 +417,7 @@ private function startProfiling(string $jobName = '') * @param string $jobName * @return void */ - private function stopProfiling(string $jobName = '') + private function stopProfiling(string $jobName = ''): void { $this->statProfiler->stop( sprintf(self::CRON_TIMERID, $jobName), @@ -445,9 +446,9 @@ private function getProfilingStat(string $jobName): string * Return job collection from data base with status 'pending'. * * @param string $groupId - * @return \Magento\Cron\Model\ResourceModel\Schedule\Collection + * @return ScheduleCollection */ - private function getPendingSchedules($groupId) + private function getPendingSchedules(string $groupId): ScheduleCollection { $jobs = $this->_config->getJobs(); $pendingJobs = $this->_scheduleFactory->create()->getCollection(); @@ -462,7 +463,7 @@ private function getPendingSchedules($groupId) * @param string $groupId * @return $this */ - private function generateSchedules($groupId) + private function generateSchedules(string $groupId): self { /** * check if schedule generation is needed @@ -533,13 +534,13 @@ protected function _generateJobs($jobs, $exists, $groupId) * @param int $currentTime * @return void */ - private function cleanupJobs($groupId, $currentTime) + private function cleanupJobs(string $groupId, int $currentTime): void { // check if history cleanup is needed $lastCleanup = (int)$this->_cache->load(self::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . $groupId); $historyCleanUp = (int)$this->getCronGroupConfigurationValue($groupId, self::XML_PATH_HISTORY_CLEANUP_EVERY); if ($lastCleanup > $this->dateTime->gmtTimestamp() - $historyCleanUp * self::SECONDS_IN_MINUTE) { - return $this; + return; } // save time history cleanup was ran with no expiration $this->_cache->save( @@ -674,7 +675,7 @@ protected function getScheduleTimeInterval($groupId) * @param string $groupId * @return void */ - private function cleanupDisabledJobs($groupId) + private function cleanupDisabledJobs(string $groupId): void { $jobs = $this->_config->getJobs(); $jobsToCleanup = []; @@ -703,7 +704,7 @@ private function cleanupDisabledJobs($groupId) * @param string $groupId * @return void */ - private function cleanupRunningJobs($groupId) + private function cleanupRunningJobs(string $groupId): void { $scheduleResource = $this->_scheduleFactory->create()->getResource(); $connection = $scheduleResource->getConnection(); @@ -716,13 +717,11 @@ private function cleanupRunningJobs($groupId) 'status' => \Magento\Cron\Model\Schedule::STATUS_ERROR, 'messages' => 'Time out' ], - $connection->quoteInto( - 'status = ? ' . - 'AND job_code IN (?) ' . - 'AND (scheduled_at < UTC_TIMESTAMP() - INTERVAL 1 DAY)', - \Magento\Cron\Model\Schedule::STATUS_RUNNING, - array_keys($jobs[$groupId]) - ) + [ + $connection->quoteInto('status = ?', \Magento\Cron\Model\Schedule::STATUS_RUNNING), + $connection->quoteInto('job_code IN (?)', array_keys($jobs[$groupId])), + 'scheduled_at < UTC_TIMESTAMP() - INTERVAL 1 DAY' + ] ); } @@ -803,13 +802,13 @@ private function isGroupInFilter($groupId): bool * @param array $jobsRoot * @param int $currentTime */ - private function processPendingJobs($groupId, $jobsRoot, $currentTime) + private function processPendingJobs(string $groupId, array $jobsRoot, int $currentTime): void { - $procesedJobs = []; + $processedJobs = []; $pendingJobs = $this->getPendingSchedules($groupId); /** @var Schedule $schedule */ foreach ($pendingJobs as $schedule) { - if (isset($procesedJobs[$schedule->getJobCode()])) { + if (isset($processedJobs[$schedule->getJobCode()])) { // process only on job per run continue; } @@ -826,7 +825,7 @@ private function processPendingJobs($groupId, $jobsRoot, $currentTime) $this->tryRunJob($scheduledTime, $currentTime, $jobConfig, $schedule, $groupId); if ($schedule->getStatus() === Schedule::STATUS_SUCCESS) { - $procesedJobs[$schedule->getJobCode()] = true; + $processedJobs[$schedule->getJobCode()] = true; } $this->retrier->execute( @@ -851,7 +850,7 @@ private function tryRunJob($scheduledTime, $currentTime, $jobConfig, $schedule, { // use sha1 to limit length // phpcs:ignore Magento2.Security.InsecureFunction - $lockName = self::LOCK_PREFIX . md5($groupId . '_' . $schedule->getJobCode()); + $lockName = self::LOCK_PREFIX . md5($groupId . '_' . $schedule->getJobCode()); try { for ($retries = self::MAX_RETRIES; $retries > 0; $retries--) { diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index 816fdb6173d8b..134d4ea04d171 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -1045,53 +1045,85 @@ public function testMissedJobsCleanedInTime() $scheduleMock->expects($this->exactly(10))->method('getResource')->willReturn($this->scheduleResourceMock); $this->scheduleFactoryMock->expects($this->exactly(11))->method('create')->willReturn($scheduleMock); + $connectionMock = $this->prepareConnectionMock($tableName); + + $this->scheduleResourceMock->expects($this->exactly(6)) + ->method('getTable') + ->with($tableName) + ->willReturn($tableName); + $this->scheduleResourceMock->expects($this->exactly(15)) + ->method('getConnection') + ->willReturn($connectionMock); + + $this->retrierMock->expects($this->exactly(5)) + ->method('execute') + ->willReturnCallback( + function ($callback) { + return $callback(); + } + ); + + $this->cronQueueObserver->execute($this->observerMock); + } + + /** + * @param string $tableName + * @return AdapterInterface|MockObject + */ + private function prepareConnectionMock(string $tableName) + { $connectionMock = $this->getMockForAbstractClass(AdapterInterface::class); $connectionMock->expects($this->exactly(5)) ->method('delete') ->withConsecutive( - [$tableName, ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1']]], - [$tableName, ['status = ?' => 'success', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]], - [$tableName, ['status = ?' => 'missed', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]], - [$tableName, ['status = ?' => 'error', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]], - [$tableName, ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null]] + [ + $tableName, + ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1']] + ], + [ + $tableName, + ['status = ?' => 'success', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] + ], + [ + $tableName, + ['status = ?' => 'missed', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] + ], + [ + $tableName, + ['status = ?' => 'error', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] + ], + [ + $tableName, + ['status = ?' => 'pending', 'job_code in (?)' => ['test_job1'], 'scheduled_at < ?' => null] + ] ) ->willReturn(1); - $connectionMock->expects($this->once()) + $connectionMock->expects($this->any()) ->method('quoteInto') - ->with( - 'status = ? AND job_code IN (?) AND (scheduled_at < UTC_TIMESTAMP() - INTERVAL 1 DAY)', - 'running', - ['test_job1'] + ->withConsecutive( + ['status = ?', \Magento\Cron\Model\Schedule::STATUS_RUNNING], + ['job_code IN (?)', ['test_job1']], ) - ->willReturn(''); + ->willReturnOnConsecutiveCalls( + "status = 'running'", + "job_code IN ('test_job1')" + ); $connectionMock->expects($this->once()) ->method('update') ->with( $tableName, ['status' => 'error', 'messages' => 'Time out'], - '' + [ + "status = 'running'", + "job_code IN ('test_job1')", + 'scheduled_at < UTC_TIMESTAMP() - INTERVAL 1 DAY' + ] ) ->willReturn(0); - $this->scheduleResourceMock->expects($this->exactly(6)) - ->method('getTable') - ->with($tableName) - ->willReturn($tableName); - $this->scheduleResourceMock->expects($this->exactly(15)) - ->method('getConnection') - ->willReturn($connectionMock); - - $this->retrierMock->expects($this->exactly(5)) - ->method('execute') - ->willReturnCallback( - function ($callback) { - return $callback(); - } - ); - - $this->cronQueueObserver->execute($this->observerMock); + return $connectionMock; } } diff --git a/app/code/Magento/Cron/etc/db_schema_whitelist.json b/app/code/Magento/Cron/etc/db_schema_whitelist.json index c8666896627e2..74836c0be8a2e 100644 --- a/app/code/Magento/Cron/etc/db_schema_whitelist.json +++ b/app/code/Magento/Cron/etc/db_schema_whitelist.json @@ -12,10 +12,11 @@ }, "index": { "CRON_SCHEDULE_JOB_CODE": true, - "CRON_SCHEDULE_SCHEDULED_AT_STATUS": true + "CRON_SCHEDULE_SCHEDULED_AT_STATUS": true, + "CRON_SCHEDULE_JOB_CODE_STATUS_SCHEDULED_AT": true }, "constraint": { "PRIMARY": true } } -} \ No newline at end of file +} From 7d6f8bb0846b863d8a2aa78b8ce1e480a7cf7413 Mon Sep 17 00:00:00 2001 From: saphaljha Date: Fri, 11 Sep 2020 11:01:41 +0530 Subject: [PATCH 007/346] Fixed issue when using dynamic elements --- .../View/Helper/SecureHtmlRenderer.php | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index ae8ab3f15bc96..d7369416f44bf 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -111,16 +111,21 @@ public function renderEventListenerAsTag( function {$listenerFunction} () { {$attributeJavascript}; } - var {$elementName} = document.querySelector("{$elementSelector}"); - if ({$elementName}) { - {$elementName}.{$eventName} = function (event) { - var targetElement = {$elementName}; - if (event && event.target) { - targetElement = event.target; + var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); + + {$elementName}Array.forEach(function(element){ + if (element) { + element.{$eventName} = function (event) { + var targetElement = element; + if (event && event.target) { + targetElement = event.target; + } + {$listenerFunction}.apply(targetElement); } - {$listenerFunction}.apply(targetElement); } - } + }); + + script; return $this->renderTag('script', ['type' => 'text/javascript'], $script, false); From 1f0fe69c7965997b43995848119a3b5ec004de27 Mon Sep 17 00:00:00 2001 From: saphaljha Date: Sat, 12 Sep 2020 20:06:59 +0530 Subject: [PATCH 008/346] Updated code for validate empty nodeList and covered MFTF --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 +++++++++++++++++++ .../Mftf/Section/AdminNewWidgetSection.xml | 4 ++ ...AddAndDeleteMultipleLayoutSectionsTest.xml | 36 ++++++++++++++++++ .../View/Helper/SecureHtmlRenderer.php | 22 +++++------ 4 files changed, 89 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml new file mode 100644 index 0000000000000..b7ebd09c2fcc6 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml @@ -0,0 +1,38 @@ + + + + + + Goes to the Admin Widget creation page. Add and delete multiple layouts + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 0777e6cbd58d9..373274aef8584 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -40,5 +40,9 @@ + + + + diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml new file mode 100644 index 0000000000000..5a5652e1e9049 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml @@ -0,0 +1,36 @@ + + + + + + + + + <description value="Admin should be able to Add and Delete multiple layouts"/> + <severity value="CRITICAL"/> + <group value="Widget"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToContentWidgetsPageFirst"> + <argument name="menuUiId" value="{{AdminMenuContent.dataUiId}}"/> + <argument name="submenuUiId" value="{{AdminMenuContentElementsWidgets.dataUiId}}"/> + </actionGroup> + <actionGroup ref="AdminAssertPageTitleActionGroup" stepKey="seePageTitleFirst"> + <argument name="title" value="{{AdminMenuContentElementsWidgets.pageTitle}}"/> + </actionGroup> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> + <actionGroup ref="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup" stepKey="addWidgetForTest"> + <argument name="widget" value="ProductsListWidget"/> + </actionGroup> + </test> +</tests> diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index d7369416f44bf..ebc4b8870538f 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -112,19 +112,19 @@ function {$listenerFunction} () { {$attributeJavascript}; } var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); - - {$elementName}Array.forEach(function(element){ - if (element) { - element.{$eventName} = function (event) { - var targetElement = element; - if (event && event.target) { - targetElement = event.target; + if({$elementName}Array.lenght !== 'undefined'){ + {$elementName}Array.forEach(function(element){ + if (element) { + element.{$eventName} = function (event) { + var targetElement = element; + if (event && event.target) { + targetElement = event.target; + } + {$listenerFunction}.apply(targetElement); } - {$listenerFunction}.apply(targetElement); } - } - }); - + }); + } script; From e95d2fefefb62150e566f000a4a17f58f6716af5 Mon Sep 17 00:00:00 2001 From: Jason Woods <devel@jasonwoods.me.uk> Date: Mon, 21 Sep 2020 16:36:46 +0100 Subject: [PATCH 009/346] Revert #27391 changes Status field is no longer used in that query after this PR --- app/code/Magento/Cron/etc/db_schema.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/code/Magento/Cron/etc/db_schema.xml b/app/code/Magento/Cron/etc/db_schema.xml index de7ebf3fc50b6..72b1428756898 100644 --- a/app/code/Magento/Cron/etc/db_schema.xml +++ b/app/code/Magento/Cron/etc/db_schema.xml @@ -26,9 +26,5 @@ <column name="status"/> <column name="scheduled_at"/> </index> - <index referenceId="CRON_SCHEDULE_SCHEDULE_ID_STATUS" indexType="btree"> - <column name="schedule_id"/> - <column name="status"/> - </index> </table> </schema> From 916bc93138f7a81f65c2e8b5069eeb0f35fceb43 Mon Sep 17 00:00:00 2001 From: Jason Woods <devel@jasonwoods.me.uk> Date: Mon, 21 Sep 2020 16:40:43 +0100 Subject: [PATCH 010/346] Revert #27391 changes Status field is no longer used in the query --- app/code/Magento/Cron/etc/db_schema_whitelist.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Cron/etc/db_schema_whitelist.json b/app/code/Magento/Cron/etc/db_schema_whitelist.json index a598c6d213c55..74836c0be8a2e 100644 --- a/app/code/Magento/Cron/etc/db_schema_whitelist.json +++ b/app/code/Magento/Cron/etc/db_schema_whitelist.json @@ -13,8 +13,7 @@ "index": { "CRON_SCHEDULE_JOB_CODE": true, "CRON_SCHEDULE_SCHEDULED_AT_STATUS": true, - "CRON_SCHEDULE_JOB_CODE_STATUS_SCHEDULED_AT": true, - "CRON_SCHEDULE_SCHEDULE_ID_STATUS": true + "CRON_SCHEDULE_JOB_CODE_STATUS_SCHEDULED_AT": true }, "constraint": { "PRIMARY": true From edd77531f8847f7b13dbaca9aefa315ba4aa5e57 Mon Sep 17 00:00:00 2001 From: Ihor Sviziev <ihor-sviziev@users.noreply.github.com> Date: Mon, 21 Sep 2020 22:23:38 +0300 Subject: [PATCH 011/346] Fix SVC failure --- app/code/Magento/Cron/etc/db_schema_whitelist.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Cron/etc/db_schema_whitelist.json b/app/code/Magento/Cron/etc/db_schema_whitelist.json index 74836c0be8a2e..2e5cc6e0a4618 100644 --- a/app/code/Magento/Cron/etc/db_schema_whitelist.json +++ b/app/code/Magento/Cron/etc/db_schema_whitelist.json @@ -13,6 +13,7 @@ "index": { "CRON_SCHEDULE_JOB_CODE": true, "CRON_SCHEDULE_SCHEDULED_AT_STATUS": true, + "CRON_SCHEDULE_SCHEDULE_ID_STATUS": true, "CRON_SCHEDULE_JOB_CODE_STATUS_SCHEDULED_AT": true }, "constraint": { From ff1a003de96805fda207c5f9c6cef95d08ba20c8 Mon Sep 17 00:00:00 2001 From: govindasharma974 <govindpokhrelsharma@cedcommerce.com> Date: Sat, 10 Oct 2020 14:11:32 +0530 Subject: [PATCH 012/346] Fixed issue related with wrong invoice id ,creditmemo id and shipmen id in url of view page. --- .../Adminhtml/Order/Creditmemo/View.php | 9 +-- .../Adminhtml/Order/CreditmemoLoader.php | 6 +- .../Adminhtml/Order/Invoice/View.php | 7 +- .../AdminGoToCreditmemoViewActionGroup.xml | 22 +++++++ ...pmentViewPageWithWrongCreditmemoIdTest.xml | 39 +++++++++++ .../Adminhtml/Order/Creditmemo/ViewTest.php | 50 +++++++++++--- .../Adminhtml/Order/Shipment/View.php | 9 +-- .../Adminhtml/Order/ShipmentLoader.php | 7 +- .../AdminGoToShipmentViewActionGroup.xml | 22 +++++++ .../Test/Mftf/Page/AdminShipmentViewPage.xml | 13 ++++ ...hipmentViewPageWithWrongShipmentIdTest.xml | 39 +++++++++++ .../Adminhtml/Order/Shipment/ViewTest.php | 65 +++++++++++++++---- 12 files changed, 254 insertions(+), 34 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongCreditmemoIdTest.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/View.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/View.php index be0afdb4a043b..c5832f64547c1 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/View.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/View.php @@ -6,8 +6,9 @@ namespace Magento\Sales\Controller\Adminhtml\Order\Creditmemo; use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; -class View extends \Magento\Backend\App\Action +class View extends \Magento\Backend\App\Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session @@ -75,9 +76,9 @@ public function execute() } return $resultPage; } else { - $resultForward = $this->resultForwardFactory->create(); - $resultForward->forward('noroute'); - return $resultForward; + $resultRedirect = $this->resultRedirectFactory->create(); + $resultRedirect->setPath('sales/creditmemo'); + return $resultRedirect; } } } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php index 0c5864e954a4f..dbcf22bc7bcf9 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php @@ -181,7 +181,11 @@ public function load() $creditmemoId = $this->getCreditmemoId(); $orderId = $this->getOrderId(); if ($creditmemoId) { - $creditmemo = $this->creditmemoRepository->get($creditmemoId); + try { + $creditmemo = $this->creditmemoRepository->get($creditmemoId); + } catch (\Exception $e) { + $this->messageManager->addErrorMessage(__('This creditmemo no longer exists.')); + return false; } elseif ($orderId) { $data = $this->getCreditmemo(); $order = $this->orderFactory->create()->load($orderId); diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/View.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/View.php index da700aae2f78a..b0e860d7f2e2d 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/View.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/View.php @@ -44,9 +44,10 @@ public function execute() { $invoice = $this->getInvoice(); if (!$invoice) { - /** @var \Magento\Framework\Controller\Result\Forward $resultForward */ - $resultForward = $this->resultForwardFactory->create(); - return $resultForward->forward('noroute'); + /** @var \Magento\Framework\Controller\Result\RedirectFactory $resultRedirect */ + $resultRedirect = $this->resultRedirectFactory->create(); + $resultRedirect->setPath('sales/invoice'); + return $resultRedirect; } /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml new file mode 100644 index 0000000000000..b55a7e8d6e5ed --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminGoToCreditmemoViewActionGroup"> + <annotations> + <description>Goes to the Order Creditmemo View Page.</description> + </annotations> + <arguments> + <argument name="identifier" type="string"/> + </arguments> + + <amOnPage url="{{AdminCreditmemoViewPage.url}}/{{identifier}}" stepKey="amOnCreditmemoViewPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongCreditmemoIdTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongCreditmemoIdTest.xml new file mode 100644 index 0000000000000..f04629708e0cd --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongCreditmemoIdTest.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest"> + <annotations> + <stories value="Creditmemo Page With Wrong Creditmemo Id"/> + <title value="Open Creditmemo View Page with Wrong Creditmemo Id"/> + <description value="Open Creditmemo View Page with Wrong Creditmemo Id."/> + <severity value="MAJOR"/> + <group value="sales"/> + </annotations> + + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + </before> + + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <actionGroup ref="AdminGoToCreditmemoViewActionGroup" stepKey="navigateOpenCreditmemoViewPage"> + <argument name="identifier" value="test"/> + </actionGroup> + + <waitForPageLoad stepKey="waitForPageLoad"/> + + <seeInCurrentUrl url="{{AdminCreditmemosGridPage.url}}" stepKey="redirectToCreditmemosGridPage"/> + + <see selector="{{AdminMessagesSection.error}}" userInput='This creditmemo no longer exists.' + stepKey="seeErrorMessage"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php index 46c3113c8edc2..e7556fe309ecf 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php @@ -13,6 +13,8 @@ use Magento\Backend\Model\View\Result\Forward; use Magento\Backend\Model\View\Result\ForwardFactory; use Magento\Backend\Model\View\Result\Page; +use Magento\Backend\Model\View\Result\Redirect; +use Magento\Backend\Model\View\Result\RedirectFactory; use Magento\Framework\App\ActionFlag; use Magento\Framework\App\Request\Http; use Magento\Framework\Message\Manager; @@ -105,6 +107,17 @@ class ViewTest extends TestCase */ protected $pageTitleMock; + /** + * @var \Magento\Shipping\Controller\Adminhtml\Order\Creditmemo\View + * @var RedirectFactory|MockObject + */ + protected $resultRedirectFactoryMock; + + /** + * @var Redirect|MockObject + */ + protected $resultRedirectMock; + /** * @var PageFactory|MockObject */ @@ -239,7 +252,8 @@ protected function setUp(): void 'context' => $this->contextMock, 'creditmemoLoader' => $this->loaderMock, 'resultPageFactory' => $this->resultPageFactoryMock, - 'resultForwardFactory' => $this->resultForwardFactoryMock + 'resultForwardFactory' => $this->resultForwardFactoryMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock ] ); } @@ -252,16 +266,11 @@ public function testExecuteNoCreditMemo() $this->loaderMock->expects($this->once()) ->method('load') ->willReturn(false); - $this->resultForwardFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->resultForwardMock); - $this->resultForwardMock->expects($this->once()) - ->method('forward') - ->with('noroute') - ->willReturnSelf(); - + + $this->prepareRedirect(); + $this->setPath('sales/creditmemo'); $this->assertInstanceOf( - Forward::class, + Redirect::class, $this->controller->execute() ); } @@ -322,4 +331,25 @@ public function executeDataProvider() [$this->invoiceMock] ]; } + + /** + * prepareRedirect + */ + protected function prepareRedirect() + { + $this->resultRedirectFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->resultRedirectMock); + } + + /** + * @param string $path + * @param array $params + */ + protected function setPath($path, $params = []) + { + $this->resultRedirectMock->expects($this->once()) + ->method('setPath') + ->with($path, $params); + } } diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php index d8fda0bfe781b..d903a1a7d5889 100644 --- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php +++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/Shipment/View.php @@ -7,8 +7,9 @@ namespace Magento\Shipping\Controller\Adminhtml\Order\Shipment; use Magento\Backend\App\Action; +use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; -class View extends \Magento\Backend\App\Action +class View extends \Magento\Backend\App\Action implements HttpGetActionInterface { /** * Authorization level of a basic admin session @@ -71,9 +72,9 @@ public function execute() $resultPage->getConfig()->getTitle()->prepend("#" . $shipment->getIncrementId()); return $resultPage; } else { - $resultForward = $this->resultForwardFactory->create(); - $resultForward->forward('noroute'); - return $resultForward; + $resultRedirect = $this->resultRedirectFactory->create(); + $resultRedirect->setPath('sales/shipment'); + return $resultRedirect; } } } diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php index c4094a63ec527..4f44bfb6458b1 100644 --- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php +++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php @@ -110,7 +110,12 @@ public function load() $orderId = $this->getOrderId(); $shipmentId = $this->getShipmentId(); if ($shipmentId) { - $shipment = $this->shipmentRepository->get($shipmentId); + try { + $shipment = $this->shipmentRepository->get($shipmentId); + } catch (\Exception $e) { + $this->messageManager->addErrorMessage(__('This shipment no longer exists.')); + return false; + } } elseif ($orderId) { $order = $this->orderRepository->get($orderId); diff --git a/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml new file mode 100644 index 0000000000000..09f74839b3a30 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminGoToShipmentViewActionGroup"> + <annotations> + <description>Goes to the Order Shipment View Page.</description> + </annotations> + <arguments> + <argument name="identifier" type="string"/> + </arguments> + + <amOnPage url="{{AdminShipmentViewPage.url}}/{{identifier}}" stepKey="amOnShipmentViewPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml new file mode 100644 index 0000000000000..5a965db2b4efe --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminShipmentViewPage" url="sales/shipment/view/shipment_id" area="admin" module="Shipping"> + </page> +</pages> \ No newline at end of file diff --git a/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml new file mode 100644 index 0000000000000..0311ebc320b59 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminOpenShipmentViewPageWithWrongShipmentIdTest"> + <annotations> + <stories value="Shipment Page With Wrong Shipment Id"/> + <title value="Open Shipment View Page with Wrong Shipment Id"/> + <description value="Open Shipment View Page with Wrong Shipment Id."/> + <severity value="MAJOR"/> + <group value="shipping"/> + </annotations> + + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + </before> + + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <actionGroup ref="AdminGoToShipmentViewActionGroup" stepKey="navigateOpenShipmentViewPage"> + <argument name="identifier" value="test"/> + </actionGroup> + + <waitForPageLoad stepKey="waitForPageLoad"/> + + <seeInCurrentUrl url="{{AdminShipmentsGridPage.url}}" stepKey="redirectToShipmentsGridPage"/> + + <see selector="{{AdminMessagesSection.error}}" userInput='This shipment no longer exists.' + stepKey="seeErrorMessage"/> + </test> +</tests> \ No newline at end of file diff --git a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php index 04b357eeaefca..d99ce83d91de2 100644 --- a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php +++ b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php @@ -11,6 +11,8 @@ use Magento\Backend\Model\View\Result\Forward; use Magento\Backend\Model\View\Result\ForwardFactory; use Magento\Backend\Model\View\Result\Page; +use Magento\Backend\Model\View\Result\Redirect; +use Magento\Backend\Model\View\Result\RedirectFactory; use Magento\Framework\App\RequestInterface; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -21,6 +23,7 @@ use Magento\Sales\Model\Order\Shipment; use Magento\Shipping\Block\Adminhtml\View; use Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader; +use Magento\Shipping\Controller\Adminhtml\Order\Shipment\View as OrderShipmentView; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -84,11 +87,24 @@ class ViewTest extends TestCase */ protected $pageTitleMock; + /** * @var \Magento\Shipping\Controller\Adminhtml\Order\Shipment\View + * @var RedirectFactory|MockObject + */ + protected $resultRedirectFactoryMock; + + /** + * @var Redirect|MockObject + */ + protected $resultRedirectMock; + + /** + * @var OrderShipmentView */ protected $controller; + protected function setUp(): void { $this->requestMock = $this->getMockBuilder(RequestInterface::class) @@ -130,16 +146,25 @@ protected function setUp(): void ['updateBackButtonUrl'] ); + $this->resultRedirectFactoryMock = $this->getMockBuilder(RedirectFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->resultRedirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); $context = $objectManager->getObject( Context::class, [ 'request' => $this->requestMock, - 'objectManager' => $this->objectManagerMock + 'objectManager' => $this->objectManagerMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock ] ); $this->controller = $objectManager->getObject( - \Magento\Shipping\Controller\Adminhtml\Order\Shipment\View::class, + OrderShipmentView::class, [ 'context' => $context, 'shipmentLoader' => $this->shipmentLoaderMock, @@ -216,15 +241,12 @@ public function testExecuteNoShipment() $tracking = []; $this->loadShipment($orderId, $shipmentId, $shipment, $tracking, null, false); - $this->resultForwardFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($this->resultForwardMock); - $this->resultForwardMock->expects($this->once()) - ->method('forward') - ->with('noroute') - ->willReturnSelf(); - - $this->assertEquals($this->resultForwardMock, $this->controller->execute()); + $this->prepareRedirect(); + $this->setPath('sales/shipment'); + $this->assertInstanceOf( + Redirect::class, + $this->controller->execute() + ); } /** @@ -255,4 +277,25 @@ protected function loadShipment($orderId, $shipmentId, $shipment, $tracking, $co ->method('load') ->willReturn($returnShipment); } + + /** + * prepareRedirect + */ + protected function prepareRedirect() + { + $this->resultRedirectFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->resultRedirectMock); + } + + /** + * @param string $path + * @param array $params + */ + protected function setPath($path, $params = []) + { + $this->resultRedirectMock->expects($this->once()) + ->method('setPath') + ->with($path, $params); + } } From 0e78fe405442b1eb8955c1e53bc2c65f539b6f63 Mon Sep 17 00:00:00 2001 From: govindasharma974 <govindpokhrelsharma@cedcommerce.com> Date: Sat, 10 Oct 2020 14:18:21 +0530 Subject: [PATCH 013/346] Fixed issue related with wrong invoice id ,creditmemo id and shipmen id in url of view page. --- ...l => AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/code/Magento/Sales/Test/Mftf/Test/{AdminOpenShipmentViewPageWithWrongCreditmemoIdTest.xml => AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml} (100%) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongCreditmemoIdTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml similarity index 100% rename from app/code/Magento/Sales/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongCreditmemoIdTest.xml rename to app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml From ff5de32bd53e7a7b7b357bf3e3606092dd777681 Mon Sep 17 00:00:00 2001 From: Govind Sharma <govindpokhrelsharma@cedcoss.com> Date: Sat, 10 Oct 2020 16:27:48 +0530 Subject: [PATCH 014/346] Update ViewTest.php --- .../Controller/Adminhtml/Order/Creditmemo/ViewTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php index e7556fe309ecf..b6935269e3da7 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php @@ -216,7 +216,13 @@ protected function setUp(): void $this->resultForwardMock = $this->getMockBuilder(Forward::class) ->disableOriginalConstructor() ->getMock(); - + $this->resultRedirectFactoryMock = $this->getMockBuilder(RedirectFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->resultRedirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); $this->contextMock->expects($this->any()) ->method('getSession') ->willReturn($this->sessionMock); From 6b1837b2db974a986f9e16264e89bf3c01fed5ea Mon Sep 17 00:00:00 2001 From: govindasharma974 <govindpokhrelsharma@cedcommerce.com> Date: Mon, 12 Oct 2020 10:47:39 +0530 Subject: [PATCH 015/346] Added new line to to mftf files, added words to csv and fixed compilation issue --- .../Adminhtml/Order/CreditmemoLoader.php | 3 +- .../AdminGoToCreditmemoViewActionGroup.xml | 2 +- ...tmemoViewPageWithWrongCreditmemoIdTest.xml | 2 +- app/code/Magento/Sales/i18n/en_US.csv | 1293 +++++++++-------- .../AdminGoToShipmentViewActionGroup.xml | 2 +- .../Test/Mftf/Page/AdminShipmentViewPage.xml | 2 +- ...hipmentViewPageWithWrongShipmentIdTest.xml | 2 +- app/code/Magento/Shipping/i18n/en_US.csv | 261 ++-- 8 files changed, 785 insertions(+), 782 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php index dbcf22bc7bcf9..7bb0b38a8d5ff 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php @@ -183,9 +183,10 @@ public function load() if ($creditmemoId) { try { $creditmemo = $this->creditmemoRepository->get($creditmemoId); - } catch (\Exception $e) { + } catch (\Exception $e) { $this->messageManager->addErrorMessage(__('This creditmemo no longer exists.')); return false; + } } elseif ($orderId) { $data = $this->getCreditmemo(); $order = $this->orderFactory->create()->load($orderId); diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml index b55a7e8d6e5ed..041ebc7baa84d 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml @@ -19,4 +19,4 @@ <amOnPage url="{{AdminCreditmemoViewPage.url}}/{{identifier}}" stepKey="amOnCreditmemoViewPage"/> <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> -</actionGroups> \ No newline at end of file +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml index f04629708e0cd..c6522cb22cdf3 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml @@ -36,4 +36,4 @@ <see selector="{{AdminMessagesSection.error}}" userInput='This creditmemo no longer exists.' stepKey="seeErrorMessage"/> </test> -</tests> \ No newline at end of file +</tests> diff --git a/app/code/Magento/Sales/i18n/en_US.csv b/app/code/Magento/Sales/i18n/en_US.csv index 97c1706f975da..059569775e419 100644 --- a/app/code/Magento/Sales/i18n/en_US.csv +++ b/app/code/Magento/Sales/i18n/en_US.csv @@ -1,344 +1,344 @@ -"Credit Memos","Credit Memos" +Credit Memos,Credit Memos Orders,Orders Invoices,Invoices -"We can't get the order instance right now.","We can't get the order instance right now." -"Create New Order","Create New Order" -"Save Order Address","Save Order Address" +We can't get the order instance right now.,We can't get the order instance right now. +Create New Order,Create New Order +Save Order Address,Save Order Address Shipping,Shipping Billing,Billing -"Edit Order %1 %2 Address","Edit Order %1 %2 Address" -"Order Address Information","Order Address Information" -"Please correct the parent block for this block.","Please correct the parent block for this block." -"Submit Comment","Submit Comment" -"Submit Order","Submit Order" -"Are you sure you want to cancel this order?","Are you sure you want to cancel this order?" +Edit Order %1 %2 Address,Edit Order %1 %2 Address +Order Address Information,Order Address Information +Please correct the parent block for this block.,Please correct the parent block for this block. +Submit Comment,Submit Comment +Submit Order,Submit Order +Are you sure you want to cancel this order?,Are you sure you want to cancel this order? Cancel,Cancel -"Billing Address","Billing Address" -"Payment Method","Payment Method" -"Order Comment","Order Comment" +Billing Address,Billing Address +Payment Method,Payment Method +Order Comment,Order Comment Coupons,Coupons -"Please select a customer","Please select a customer" -"Create New Customer","Create New Customer" -"Account Information","Account Information" +Please select a customer,Please select a customer +Create New Customer,Create New Customer +Account Information,Account Information From,From To,To Message,Message -"Edit Order #%1","Edit Order #%1" -"Create New Order for %1 in %2","Create New Order for %1 in %2" -"Create New Order in %1","Create New Order in %1" -"Create New Order for %1","Create New Order for %1" -"Create New Order for New Customer","Create New Order for New Customer" -"Items Ordered","Items Ordered" -"This product is disabled.","This product is disabled." -"Buy %1 for price %2","Buy %1 for price %2" -"Item ordered qty","Item ordered qty" -"%1 with %2 discount each","%1 with %2 discount each" -"%1 for %2","%1 for %2" -"* - Enter custom price including tax","* - Enter custom price including tax" -"* - Enter custom price excluding tax","* - Enter custom price excluding tax" +Edit Order #%1,Edit Order #%1 +Create New Order for %1 in %2,Create New Order for %1 in %2 +Create New Order in %1,Create New Order in %1 +Create New Order for %1,Create New Order for %1 +Create New Order for New Customer,Create New Order for New Customer +Items Ordered,Items Ordered +This product is disabled.,This product is disabled. +Buy %1 for price %2,Buy %1 for price %2 +Item ordered qty,Item ordered qty +%1 with %2 discount each,%1 with %2 discount each +%1 for %2,%1 for %2 +* - Enter custom price including tax,* - Enter custom price including tax +* - Enter custom price excluding tax,* - Enter custom price excluding tax Configure,Configure -"This product does not have any configurable options","This product does not have any configurable options" -"Newsletter Subscription","Newsletter Subscription" -"Please select products","Please select products" -"Add Selected Product(s) to Order","Add Selected Product(s) to Order" +This product does not have any configurable options,This product does not have any configurable options +Newsletter Subscription,Newsletter Subscription +Please select products,Please select products +Add Selected Product(s) to Order,Add Selected Product(s) to Order ID,ID Product,Product SKU,SKU Price,Price Select,Select Quantity,Quantity -"Shipping Address","Shipping Address" -"Shipping Method","Shipping Method" -"Update Changes","Update Changes" -"Shopping Cart","Shopping Cart" -"Are you sure you want to delete all items from shopping cart?","Are you sure you want to delete all items from shopping cart?" -"Clear Shopping Cart","Clear Shopping Cart" -"Products in Comparison List","Products in Comparison List" -"Recently Compared Products","Recently Compared Products" -"Recently Viewed Products","Recently Viewed Products" -"Last Ordered Items","Last Ordered Items" -"Recently Viewed","Recently Viewed" -"Wish List","Wish List" -"Please select a store","Please select a store" -"Order Totals","Order Totals" -"Shipping Incl. Tax (%1)","Shipping Incl. Tax (%1)" -"Shipping Excl. Tax (%1)","Shipping Excl. Tax (%1)" -"New Credit Memo for Invoice #%1","New Credit Memo for Invoice #%1" -"New Credit Memo for Order #%1","New Credit Memo for Order #%1" -"Refund Shipping (Incl. Tax)","Refund Shipping (Incl. Tax)" -"Refund Shipping (Excl. Tax)","Refund Shipping (Excl. Tax)" -"Refund Shipping","Refund Shipping" -"Update Qty's","Update Qty's" +Shipping Address,Shipping Address +Shipping Method,Shipping Method +Update Changes,Update Changes +Shopping Cart,Shopping Cart +Are you sure you want to delete all items from shopping cart?,Are you sure you want to delete all items from shopping cart? +Clear Shopping Cart,Clear Shopping Cart +Products in Comparison List,Products in Comparison List +Recently Compared Products,Recently Compared Products +Recently Viewed Products,Recently Viewed Products +Last Ordered Items,Last Ordered Items +Recently Viewed,Recently Viewed +Wish List,Wish List +Please select a store,Please select a store +Order Totals,Order Totals +Shipping Incl. Tax (%1),Shipping Incl. Tax (%1) +Shipping Excl. Tax (%1),Shipping Excl. Tax (%1) +New Credit Memo for Invoice #%1,New Credit Memo for Invoice #%1 +New Credit Memo for Order #%1,New Credit Memo for Order #%1 +Refund Shipping (Incl. Tax),Refund Shipping (Incl. Tax) +Refund Shipping (Excl. Tax),Refund Shipping (Excl. Tax) +Refund Shipping,Refund Shipping +Update Qty's,Update Qty's Refund,Refund -"Refund Offline","Refund Offline" -"Paid Amount","Paid Amount" -"Refund Amount","Refund Amount" -"Shipping Amount","Shipping Amount" -"Shipping Refund","Shipping Refund" -"Order Grand Total","Order Grand Total" -"Adjustment Refund","Adjustment Refund" -"Adjustment Fee","Adjustment Fee" -"Send Email","Send Email" -"Are you sure you want to send a credit memo email to customer?","Are you sure you want to send a credit memo email to customer?" +Refund Offline,Refund Offline +Paid Amount,Paid Amount +Refund Amount,Refund Amount +Shipping Amount,Shipping Amount +Shipping Refund,Shipping Refund +Order Grand Total,Order Grand Total +Adjustment Refund,Adjustment Refund +Adjustment Fee,Adjustment Fee +Send Email,Send Email +Are you sure you want to send a credit memo email to customer?,Are you sure you want to send a credit memo email to customer? Void,Void Print,Print -"The credit memo email was sent.","The credit memo email was sent." -"The credit memo email wasn't sent.","The credit memo email wasn't sent." -"Credit Memo #%1 | %3 | %2 (%4)","Credit Memo #%1 | %3 | %2 (%4)" -"Total Refund","Total Refund" -"New Invoice and Shipment for Order #%1","New Invoice and Shipment for Order #%1" -"New Invoice for Order #%1","New Invoice for Order #%1" -"Submit Invoice and Shipment","Submit Invoice and Shipment" -"Submit Invoice","Submit Invoice" -"Are you sure you want to send an invoice email to customer?","Are you sure you want to send an invoice email to customer?" -"Credit Memo","Credit Memo" +The credit memo email was sent.,The credit memo email was sent. +The credit memo email wasn't sent.,The credit memo email wasn't sent. +Credit Memo #%1 | %3 | %2 (%4),Credit Memo #%1 | %3 | %2 (%4) +Total Refund,Total Refund +New Invoice and Shipment for Order #%1,New Invoice and Shipment for Order #%1 +New Invoice for Order #%1,New Invoice for Order #%1 +Submit Invoice and Shipment,Submit Invoice and Shipment +Submit Invoice,Submit Invoice +Are you sure you want to send an invoice email to customer?,Are you sure you want to send an invoice email to customer? +Credit Memo,Credit Memo Capture,Capture -"The invoice email was sent.","The invoice email was sent." -"The invoice email wasn't sent.","The invoice email wasn't sent." -"Invoice #%1 | %2 | %4 (%3)","Invoice #%1 | %2 | %4 (%3)" -"Invalid parent block for this block","Invalid parent block for this block" -"Order Statuses","Order Statuses" -"Create New Status","Create New Status" -"Assign Status to State","Assign Status to State" -"Save Status Assignment","Save Status Assignment" -"Assign Order Status to State","Assign Order Status to State" -"Assignment Information","Assignment Information" -"Order Status","Order Status" -"Order State","Order State" -"Use Order Status As Default","Use Order Status As Default" -"Visible On Storefront","Visible On Storefront" -"Edit Order Status","Edit Order Status" -"Save Status","Save Status" -"New Order Status","New Order Status" -"Order Status Information","Order Status Information" -"Status Code","Status Code" -"Status Label","Status Label" -"Store View Specific Labels","Store View Specific Labels" -"Total Paid","Total Paid" -"Total Refunded","Total Refunded" -"Total Due","Total Due" -"Total Canceled","Total Canceled" +The invoice email was sent.,The invoice email was sent. +The invoice email wasn't sent.,The invoice email wasn't sent. +Invoice #%1 | %2 | %4 (%3),Invoice #%1 | %2 | %4 (%3) +Invalid parent block for this block,Invalid parent block for this block +Order Statuses,Order Statuses +Create New Status,Create New Status +Assign Status to State,Assign Status to State +Save Status Assignment,Save Status Assignment +Assign Order Status to State,Assign Order Status to State +Assignment Information,Assignment Information +Order Status,Order Status +Order State,Order State +Use Order Status As Default,Use Order Status As Default +Visible On Storefront,Visible On Storefront +Edit Order Status,Edit Order Status +Save Status,Save Status +New Order Status,New Order Status +Order Status Information,Order Status Information +Status Code,Status Code +Status Label,Status Label +Store View Specific Labels,Store View Specific Labels +Total Paid,Total Paid +Total Refunded,Total Refunded +Total Due,Total Due +Total Canceled,Total Canceled Edit,Edit -"Are you sure you want to send an order email to customer?","Are you sure you want to send an order email to customer?" +Are you sure you want to send an order email to customer?,Are you sure you want to send an order email to customer? "This will create an offline refund. To create an online refund, open an invoice and create credit memo for it. Do you want to continue?","This will create an offline refund. To create an online refund, open an invoice and create credit memo for it. Do you want to continue?" -"Are you sure you want to void the payment?","Are you sure you want to void the payment?" +Are you sure you want to void the payment?,Are you sure you want to void the payment? Hold,Hold hold,hold Unhold,Unhold unhold,unhold -"Are you sure you want to accept this payment?","Are you sure you want to accept this payment?" -"Accept Payment","Accept Payment" -"Are you sure you want to deny this payment?","Are you sure you want to deny this payment?" -"Deny Payment","Deny Payment" -"Get Payment Update","Get Payment Update" -"Invoice and Ship","Invoice and Ship" +Are you sure you want to accept this payment?,Are you sure you want to accept this payment? +Accept Payment,Accept Payment +Are you sure you want to deny this payment?,Are you sure you want to deny this payment? +Deny Payment,Deny Payment +Get Payment Update,Get Payment Update +Invoice and Ship,Invoice and Ship Invoice,Invoice Ship,Ship Reorder,Reorder -"Order # %1 %2 | %3","Order # %1 %2 | %3" +Order # %1 %2 | %3,Order # %1 %2 | %3 "This order contains (%1) items and therefore cannot be edited through the admin interface. If you wish to continue editing, the (%2) items will be removed, the order will be canceled and a new order will be placed.","This order contains (%1) items and therefore cannot be edited through the admin interface. If you wish to continue editing, the (%2) items will be removed, the order will be canceled and a new order will be placed." -"Are you sure? This order will be canceled and a new one will be created instead.","Are you sure? This order will be canceled and a new one will be created instead." -"Save Gift Message","Save Gift Message" -" [deleted]"," [deleted]" -"Order Credit Memos","Order Credit Memos" -"Credit memo #%1 created","Credit memo #%1 created" -"Credit memo #%1 comment added","Credit memo #%1 comment added" -"Shipment #%1 created","Shipment #%1 created" -"Shipment #%1 comment added","Shipment #%1 comment added" -"Invoice #%1 created","Invoice #%1 created" -"Invoice #%1 comment added","Invoice #%1 comment added" -"Tracking number %1 for %2 assigned","Tracking number %1 for %2 assigned" -"Comments History","Comments History" -"Order History","Order History" +Are you sure? This order will be canceled and a new one will be created instead.,Are you sure? This order will be canceled and a new one will be created instead. +Save Gift Message,Save Gift Message + [deleted], [deleted] +Order Credit Memos,Order Credit Memos +Credit memo #%1 created,Credit memo #%1 created +Credit memo #%1 comment added,Credit memo #%1 comment added +Shipment #%1 created,Shipment #%1 created +Shipment #%1 comment added,Shipment #%1 comment added +Invoice #%1 created,Invoice #%1 created +Invoice #%1 comment added,Invoice #%1 comment added +Tracking number %1 for %2 assigned,Tracking number %1 for %2 assigned +Comments History,Comments History +Order History,Order History Information,Information -"Order Information","Order Information" -"Order Invoices","Order Invoices" +Order Information,Order Information +Order Invoices,Order Invoices Shipments,Shipments -"Order Shipments","Order Shipments" +Order Shipments,Order Shipments Transactions,Transactions -"Order View","Order View" +Order View,Order View Any,Any Specified,Specified -"Applies to Any of the Specified Order Statuses except canceled orders","Applies to Any of the Specified Order Statuses except canceled orders" -"Cart Price Rule","Cart Price Rule" +Applies to Any of the Specified Order Statuses except canceled orders,Applies to Any of the Specified Order Statuses except canceled orders +Cart Price Rule,Cart Price Rule Yes,Yes No,No -"Show Actual Values","Show Actual Values" -"New Order RSS","New Order RSS" +Show Actual Values,Show Actual Values +New Order RSS,New Order RSS Subtotal,Subtotal -"Shipping & Handling","Shipping & Handling" -"Discount (%1)","Discount (%1)" +Shipping & Handling,Shipping & Handling +Discount (%1),Discount (%1) Discount,Discount -"Grand Total","Grand Total" +Grand Total,Grand Total Back,Back Fetch,Fetch -"Transaction # %1 | %2","Transaction # %1 | %2" +Transaction # %1 | %2,Transaction # %1 | %2 N/A,N/A Key,Key Value,Value -"We found an invalid entity model.","We found an invalid entity model." -"Order # %1","Order # %1" -"Back to My Orders","Back to My Orders" -"View Another Order","View Another Order" -"About Your Refund","About Your Refund" -"My Orders","My Orders" -"Subscribe to Order Status","Subscribe to Order Status" -"About Your Invoice","About Your Invoice" -"Print Order # %1","Print Order # %1" -"Grand Total to be Charged","Grand Total to be Charged" +We found an invalid entity model.,We found an invalid entity model. +Order # %1,Order # %1 +Back to My Orders,Back to My Orders +View Another Order,View Another Order +About Your Refund,About Your Refund +My Orders,My Orders +Subscribe to Order Status,Subscribe to Order Status +About Your Invoice,About Your Invoice +Print Order # %1,Print Order # %1 +Grand Total to be Charged,Grand Total to be Charged Unassign,Unassign -"We can't add this item to your shopping cart right now.","We can't add this item to your shopping cart right now." -"You sent the message.","You sent the message." +We can't add this item to your shopping cart right now.,We can't add this item to your shopping cart right now. +You sent the message.,You sent the message. Sales,Sales -"Invoice capturing error","Invoice capturing error" -"This order no longer exists.","This order no longer exists." -"Please enter a comment.","Please enter a comment." -"We cannot add order history.","We cannot add order history." -"You updated the order address.","You updated the order address." -"We can't update the order address right now.","We can't update the order address right now." -"You have not canceled the item.","You have not canceled the item." -"You canceled the order.","You canceled the order." +Invoice capturing error,Invoice capturing error +This order no longer exists.,This order no longer exists. +Please enter a comment.,Please enter a comment. +We cannot add order history.,We cannot add order history. +You updated the order address.,You updated the order address. +We can't update the order address right now.,We can't update the order address right now. +You have not canceled the item.,You have not canceled the item. +You canceled the order.,You canceled the order. """%1"" coupon code was not applied. Do not apply discount is selected for item(s)","""%1"" coupon code was not applied. Do not apply discount is selected for item(s)" """%1"" coupon code is not valid.","""%1"" coupon code is not valid." -"The coupon code has been accepted.","The coupon code has been accepted." -"Quote item id is not received.","Quote item id is not received." -"Quote item is not loaded.","Quote item is not loaded." -"New Order","New Order" -"You created the order.","You created the order." -"Order saving error: %1","Order saving error: %1" -"Cannot add new comment.","Cannot add new comment." -"The credit memo has been canceled.","The credit memo has been canceled." -"Credit memo has not been canceled.","Credit memo has not been canceled." -"New Memo for #%1","New Memo for #%1" -"New Memo","New Memo" -"The credit memo's total must be positive.","The credit memo's total must be positive." -"Cannot create online refund for Refund to Store Credit.","Cannot create online refund for Refund to Store Credit." -"You created the credit memo.","You created the credit memo." -"We can't save the credit memo right now.","We can't save the credit memo right now." -"We can't update the item's quantity right now.","We can't update the item's quantity right now." -"View Memo for #%1","View Memo for #%1" -"View Memo","View Memo" -"You voided the credit memo.","You voided the credit memo." -"We can't void the credit memo.","We can't void the credit memo." -"The order no longer exists.","The order no longer exists." -"We can't create credit memo for the order.","We can't create credit memo for the order." -"Edit Order","Edit Order" -"You sent the order email.","You sent the order email." -"We can't send the email order right now.","We can't send the email order right now." -"You have not put the order on hold.","You have not put the order on hold." -"You put the order on hold.","You put the order on hold." -"You canceled the invoice.","You canceled the invoice." -"Invoice canceling error","Invoice canceling error" -"The invoice has been captured.","The invoice has been captured." -"The order does not allow an invoice to be created.","The order does not allow an invoice to be created." -"You can't create an invoice without products.","You can't create an invoice without products." -"New Invoice","New Invoice" -"We can't save the invoice right now.","We can't save the invoice right now." -"You created the invoice and shipment.","You created the invoice and shipment." -"The invoice has been created.","The invoice has been created." -"We can't send the invoice email right now.","We can't send the invoice email right now." -"We can't send the shipment right now.","We can't send the shipment right now." -"Cannot update item quantity.","Cannot update item quantity." -"The invoice has been voided.","The invoice has been voided." -"Invoice voiding error","Invoice voiding error" -"%1 order(s) cannot be canceled.","%1 order(s) cannot be canceled." -"You cannot cancel the order(s).","You cannot cancel the order(s)." -"We canceled %1 order(s).","We canceled %1 order(s)." -"%1 order(s) were not put on hold.","%1 order(s) were not put on hold." -"No order(s) were put on hold.","No order(s) were put on hold." -"You have put %1 order(s) on hold.","You have put %1 order(s) on hold." -"%1 order(s) were not released from on hold status.","%1 order(s) were not released from on hold status." -"No order(s) were released from on hold status.","No order(s) were released from on hold status." -"%1 order(s) have been released from on hold status.","%1 order(s) have been released from on hold status." -"There are no printable documents related to selected orders.","There are no printable documents related to selected orders." -"The payment has been accepted.","The payment has been accepted." -"The payment has been denied.","The payment has been denied." -"Transaction has been approved.","Transaction has been approved." -"Transaction has been voided/declined.","Transaction has been voided/declined." -"There is no update for the transaction.","There is no update for the transaction." -"We can't update the payment right now.","We can't update the payment right now." -"You assigned the order status.","You assigned the order status." -"Something went wrong while assigning the order status.","Something went wrong while assigning the order status." -"We can't find this order status.","We can't find this order status." -"Create New Order Status","Create New Order Status" -"We found another order status with the same order status code.","We found another order status with the same order status code." -"You saved the order status.","You saved the order status." -"We can't add the order status right now.","We can't add the order status right now." -"You have unassigned the order status.","You have unassigned the order status." -"Something went wrong while unassigning the order.","Something went wrong while unassigning the order." -"Can't unhold order.","Can't unhold order." -"You released the order from holding status.","You released the order from holding status." -"The order was not on hold.","The order was not on hold." -"Exception occurred during order load","Exception occurred during order load" -"Something went wrong while saving the gift message.","Something went wrong while saving the gift message." -"You saved the gift card message.","You saved the gift card message." -"The payment has been voided.","The payment has been voided." -"We can't void the payment right now.","We can't void the payment right now." -"Please correct the transaction ID and try again.","Please correct the transaction ID and try again." -"The transaction details have been updated.","The transaction details have been updated." -"We can't update the transaction details.","We can't update the transaction details." -"Orders and Returns","Orders and Returns" -"You entered incorrect data. Please try again.","You entered incorrect data. Please try again." +The coupon code has been accepted.,The coupon code has been accepted. +Quote item id is not received.,Quote item id is not received. +Quote item is not loaded.,Quote item is not loaded. +New Order,New Order +You created the order.,You created the order. +Order saving error: %1,Order saving error: %1 +Cannot add new comment.,Cannot add new comment. +The credit memo has been canceled.,The credit memo has been canceled. +Credit memo has not been canceled.,Credit memo has not been canceled. +New Memo for #%1,New Memo for #%1 +New Memo,New Memo +The credit memo's total must be positive.,The credit memo's total must be positive. +Cannot create online refund for Refund to Store Credit.,Cannot create online refund for Refund to Store Credit. +You created the credit memo.,You created the credit memo. +We can't save the credit memo right now.,We can't save the credit memo right now. +We can't update the item's quantity right now.,We can't update the item's quantity right now. +View Memo for #%1,View Memo for #%1 +View Memo,View Memo +You voided the credit memo.,You voided the credit memo. +We can't void the credit memo.,We can't void the credit memo. +The order no longer exists.,The order no longer exists. +We can't create credit memo for the order.,We can't create credit memo for the order. +Edit Order,Edit Order +You sent the order email.,You sent the order email. +We can't send the email order right now.,We can't send the email order right now. +You have not put the order on hold.,You have not put the order on hold. +You put the order on hold.,You put the order on hold. +You canceled the invoice.,You canceled the invoice. +Invoice canceling error,Invoice canceling error +The invoice has been captured.,The invoice has been captured. +The order does not allow an invoice to be created.,The order does not allow an invoice to be created. +You can't create an invoice without products.,You can't create an invoice without products. +New Invoice,New Invoice +We can't save the invoice right now.,We can't save the invoice right now. +You created the invoice and shipment.,You created the invoice and shipment. +The invoice has been created.,The invoice has been created. +We can't send the invoice email right now.,We can't send the invoice email right now. +We can't send the shipment right now.,We can't send the shipment right now. +Cannot update item quantity.,Cannot update item quantity. +The invoice has been voided.,The invoice has been voided. +Invoice voiding error,Invoice voiding error +%1 order(s) cannot be canceled.,%1 order(s) cannot be canceled. +You cannot cancel the order(s).,You cannot cancel the order(s). +We canceled %1 order(s).,We canceled %1 order(s). +%1 order(s) were not put on hold.,%1 order(s) were not put on hold. +No order(s) were put on hold.,No order(s) were put on hold. +You have put %1 order(s) on hold.,You have put %1 order(s) on hold. +%1 order(s) were not released from on hold status.,%1 order(s) were not released from on hold status. +No order(s) were released from on hold status.,No order(s) were released from on hold status. +%1 order(s) have been released from on hold status.,%1 order(s) have been released from on hold status. +There are no printable documents related to selected orders.,There are no printable documents related to selected orders. +The payment has been accepted.,The payment has been accepted. +The payment has been denied.,The payment has been denied. +Transaction has been approved.,Transaction has been approved. +Transaction has been voided/declined.,Transaction has been voided/declined. +There is no update for the transaction.,There is no update for the transaction. +We can't update the payment right now.,We can't update the payment right now. +You assigned the order status.,You assigned the order status. +Something went wrong while assigning the order status.,Something went wrong while assigning the order status. +We can't find this order status.,We can't find this order status. +Create New Order Status,Create New Order Status +We found another order status with the same order status code.,We found another order status with the same order status code. +You saved the order status.,You saved the order status. +We can't add the order status right now.,We can't add the order status right now. +You have unassigned the order status.,You have unassigned the order status. +Something went wrong while unassigning the order.,Something went wrong while unassigning the order. +Can't unhold order.,Can't unhold order. +You released the order from holding status.,You released the order from holding status. +The order was not on hold.,The order was not on hold. +Exception occurred during order load,Exception occurred during order load +Something went wrong while saving the gift message.,Something went wrong while saving the gift message. +You saved the gift card message.,You saved the gift card message. +The payment has been voided.,The payment has been voided. +We can't void the payment right now.,We can't void the payment right now. +Please correct the transaction ID and try again.,Please correct the transaction ID and try again. +The transaction details have been updated.,The transaction details have been updated. +We can't update the transaction details.,We can't update the transaction details. +Orders and Returns,Orders and Returns +You entered incorrect data. Please try again.,You entered incorrect data. Please try again. Home,Home -"Go to Home Page","Go to Home Page" -"We can't find this wish list.","We can't find this wish list." +Go to Home Page,Go to Home Page +We can't find this wish list.,We can't find this wish list. "We could not add a product to cart by the ID ""%1"".","We could not add a product to cart by the ID ""%1""." -"There is an error in one of the option rows.","There is an error in one of the option rows." -"Shipping Address: ","Shipping Address: " -"Billing Address: ","Billing Address: " -"Please specify order items.","Please specify order items." -"Please specify a shipping method.","Please specify a shipping method." -"Please specify a payment method.","Please specify a payment method." -"This payment method is not available.","This payment method is not available." -"Validation is failed.","Validation is failed." -"You did not email your customer. Please check your email settings.","You did not email your customer. Please check your email settings." -"-- Please Select --","-- Please Select --" +There is an error in one of the option rows.,There is an error in one of the option rows. +Shipping Address: ,Shipping Address: +Billing Address: ,Billing Address: +Please specify order items.,Please specify order items. +Please specify a shipping method.,Please specify a shipping method. +Please specify a payment method.,Please specify a payment method. +This payment method is not available.,This payment method is not available. +Validation is failed.,Validation is failed. +You did not email your customer. Please check your email settings.,You did not email your customer. Please check your email settings. +-- Please Select --,-- Please Select -- "Path ""%1"" is not part of allowed directory ""%2""","Path ""%1"" is not part of allowed directory ""%2""" -"Identifying Fields required","Identifying Fields required" -"Id required","Id required" +Identifying Fields required,Identifying Fields required +Id required,Id required """Invoice Document Validation Error(s):\n"" .","""Invoice Document Validation Error(s):\n"" ." "Could not save an invoice, see error log for details","Could not save an invoice, see error log for details" -"A hold action is not available.","A hold action is not available." -"You cannot remove the hold.","You cannot remove the hold." -"We cannot cancel this order.","We cannot cancel this order." +A hold action is not available.,A hold action is not available. +You cannot remove the hold.,You cannot remove the hold. +We cannot cancel this order.,We cannot cancel this order. Guest,Guest -"Please enter the first name.","Please enter the first name." -"Please enter the last name.","Please enter the last name." -"Please enter the street.","Please enter the street." -"Please enter the city.","Please enter the city." -"Please enter the phone number.","Please enter the phone number." -"Please enter the company.","Please enter the company." -"Please enter the fax number.","Please enter the fax number." -"Please enter the zip/postal code.","Please enter the zip/postal code." -"Please enter the country.","Please enter the country." -"Please enter the state/province.","Please enter the state/province." -"Requested entity doesn't exist","Requested entity doesn't exist" -"Could not delete order address","Could not delete order address" -"Could not save order address","Could not save order address" +Please enter the first name.,Please enter the first name. +Please enter the last name.,Please enter the last name. +Please enter the street.,Please enter the street. +Please enter the city.,Please enter the city. +Please enter the phone number.,Please enter the phone number. +Please enter the company.,Please enter the company. +Please enter the fax number.,Please enter the fax number. +Please enter the zip/postal code.,Please enter the zip/postal code. +Please enter the country.,Please enter the country. +Please enter the state/province.,Please enter the state/province. +Requested entity doesn't exist,Requested entity doesn't exist +Could not delete order address,Could not delete order address +Could not save order address,Could not save order address Pending,Pending Refunded,Refunded Canceled,Canceled -"Unknown State","Unknown State" +Unknown State,Unknown State "We found an invalid quantity to refund item ""%1"".","We found an invalid quantity to refund item ""%1""." -"The creditmemo contains product item that is not part of the original order.","The creditmemo contains product item that is not part of the original order." -"The quantity to refund must not be greater than the unrefunded quantity.","The quantity to refund must not be greater than the unrefunded quantity." -"Maximum shipping amount allowed to refund is: %1","Maximum shipping amount allowed to refund is: %1" -"Order Id is required for creditmemo document","Order Id is required for creditmemo document" +The creditmemo contains product item that is not part of the original order.,The creditmemo contains product item that is not part of the original order. +The quantity to refund must not be greater than the unrefunded quantity.,The quantity to refund must not be greater than the unrefunded quantity. +Maximum shipping amount allowed to refund is: %1,Maximum shipping amount allowed to refund is: %1 +Order Id is required for creditmemo document,Order Id is required for creditmemo document "The creditmemo contains product SKU ""%1"" that is not part of the original order.","The creditmemo contains product SKU ""%1"" that is not part of the original order." "The quantity to creditmemo must not be greater than the unrefunded quantity for product SKU ""%1"".","The quantity to creditmemo must not be greater than the unrefunded quantity for product SKU ""%1""." -"You can't create a creditmemo without products.","You can't create a creditmemo without products." -"The most money available to refund is %1.","The most money available to refund is %1." -"Could not delete credit memo","Could not delete credit memo" -"Could not save credit memo","Could not save credit memo" -"This order already has associated customer account","This order already has associated customer account" +You can't create a creditmemo without products.,You can't create a creditmemo without products. +The most money available to refund is %1.,The most money available to refund is %1. +Could not delete credit memo,Could not delete credit memo +Could not save credit memo,Could not save credit memo +This order already has associated customer account,This order already has associated customer account Paid,Paid -"We cannot register an existing invoice","We cannot register an existing invoice" -"We can't create creditmemo for the invoice.","We can't create creditmemo for the invoice." -"Order Id is required for invoice document","Order Id is required for invoice document" +We cannot register an existing invoice,We cannot register an existing invoice +We can't create creditmemo for the invoice.,We can't create creditmemo for the invoice. +Order Id is required for invoice document,Order Id is required for invoice document "The quantity to invoice must not be greater than the uninvoiced quantity for product SKU ""%1"".","The quantity to invoice must not be greater than the uninvoiced quantity for product SKU ""%1""." -"The invoice contains one or more items that are not part of the original order.","The invoice contains one or more items that are not part of the original order." -"ID required","ID required" -"Unknown Status","Unknown Status" +The invoice contains one or more items that are not part of the original order.,The invoice contains one or more items that are not part of the original order. +ID required,ID required +Unknown Status,Unknown Status Ordered,Ordered Shipped,Shipped Invoiced,Invoiced @@ -346,460 +346,461 @@ Backordered,Backordered Returned,Returned Partial,Partial Mixed,Mixed -"Registered a Void notification.","Registered a Void notification." +Registered a Void notification.,Registered a Void notification. "If the invoice was created offline, try creating an offline credit memo.","If the invoice was created offline, try creating an offline credit memo." -"We refunded %1 online.","We refunded %1 online." -"We refunded %1 offline.","We refunded %1 offline." +We refunded %1 online.,We refunded %1 online. +We refunded %1 offline.,We refunded %1 offline. "IPN ""Refunded"". Refund issued by merchant. Registered notification about refunded amount of %1. Transaction ID: ""%2"". Credit Memo has not been created. Please create offline Credit Memo.","IPN ""Refunded"". Refund issued by merchant. Registered notification about refunded amount of %1. Transaction ID: ""%2"". Credit Memo has not been created. Please create offline Credit Memo." -"The credit memo has been created automatically.","The credit memo has been created automatically." -"Registered notification about refunded amount of %1.","Registered notification about refunded amount of %1." -"Canceled order online","Canceled order online" -"Canceled order offline","Canceled order offline" -"Approved the payment online.","Approved the payment online." -"There is no need to approve this payment.","There is no need to approve this payment." -"Denied the payment online","Denied the payment online" -"Registered update about approved payment.","Registered update about approved payment." -"Registered update about denied payment.","Registered update about denied payment." -"There is no update for the payment.","There is no update for the payment." -"Voided authorization.","Voided authorization." -"Amount: %1.","Amount: %1." +The credit memo has been created automatically.,The credit memo has been created automatically. +Registered notification about refunded amount of %1.,Registered notification about refunded amount of %1. +Canceled order online,Canceled order online +Canceled order offline,Canceled order offline +Approved the payment online.,Approved the payment online. +There is no need to approve this payment.,There is no need to approve this payment. +Denied the payment online,Denied the payment online +Registered update about approved payment.,Registered update about approved payment. +Registered update about denied payment.,Registered update about denied payment. +There is no update for the payment.,There is no update for the payment. +Voided authorization.,Voided authorization. +Amount: %1.,Amount: %1. "Transaction ID: ""%1""","Transaction ID: ""%1""" -"The payment method you requested is not available.","The payment method you requested is not available." -"The payment disallows storing objects.","The payment disallows storing objects." +The payment method you requested is not available.,The payment method you requested is not available. +The payment disallows storing objects.,The payment disallows storing objects. "The transaction ""%1"" cannot be captured yet.","The transaction ""%1"" cannot be captured yet." -"The order amount of %1 is pending approval on the payment gateway.","The order amount of %1 is pending approval on the payment gateway." -"Ordered amount of %1","Ordered amount of %1" -"An amount of %1 will be captured after being approved at the payment gateway.","An amount of %1 will be captured after being approved at the payment gateway." -"Registered notification about captured amount of %1.","Registered notification about captured amount of %1." -"Order is suspended as its capture amount %1 is suspected to be fraudulent.","Order is suspended as its capture amount %1 is suspected to be fraudulent." -"The parent transaction ID must have a transaction ID.","The parent transaction ID must have a transaction ID." -"Payment transactions disallow storing objects.","Payment transactions disallow storing objects." +The order amount of %1 is pending approval on the payment gateway.,The order amount of %1 is pending approval on the payment gateway. +Ordered amount of %1,Ordered amount of %1 +An amount of %1 will be captured after being approved at the payment gateway.,An amount of %1 will be captured after being approved at the payment gateway. +Registered notification about captured amount of %1.,Registered notification about captured amount of %1. +Order is suspended as its capture amount %1 is suspected to be fraudulent.,Order is suspended as its capture amount %1 is suspected to be fraudulent. +The parent transaction ID must have a transaction ID.,The parent transaction ID must have a transaction ID. +Payment transactions disallow storing objects.,Payment transactions disallow storing objects. "The transaction ""%1"" (%2) is already closed.","The transaction ""%1"" (%2) is already closed." -"Set order for existing transactions not allowed","Set order for existing transactions not allowed" +Set order for existing transactions not allowed,Set order for existing transactions not allowed "At minimum, you need to set a payment ID.","At minimum, you need to set a payment ID." Order,Order Authorization,Authorization "We found an unsupported transaction type ""%1"".","We found an unsupported transaction type ""%1""." -"Please set a proper payment and order id.","Please set a proper payment and order id." -"Please enter a Transaction ID.","Please enter a Transaction ID." -"You can't do this without a transaction object.","You can't do this without a transaction object." -"Order # ","Order # " -"Order Date: ","Order Date: " -"Sold to:","Sold to:" -"Ship to:","Ship to:" -"Payment Method:","Payment Method:" -"Shipping Method:","Shipping Method:" -"Total Shipping Charges","Total Shipping Charges" +Please set a proper payment and order id.,Please set a proper payment and order id. +Please enter a Transaction ID.,Please enter a Transaction ID. +You can't do this without a transaction object.,You can't do this without a transaction object. +Order # ,Order # +Order Date: ,Order Date: +Sold to:,Sold to: +Ship to:,Ship to: +Payment Method:,Payment Method: +Shipping Method:,Shipping Method: +Total Shipping Charges,Total Shipping Charges Title,Title Number,Number -"We found an invalid renderer model.","We found an invalid renderer model." -"Please define the PDF object before using.","Please define the PDF object before using." +We found an invalid renderer model.,We found an invalid renderer model. +Please define the PDF object before using.,Please define the PDF object before using. "We don't recognize the draw line data. Please define the ""lines"" array.","We don't recognize the draw line data. Please define the ""lines"" array." Products,Products -"Total (ex)","Total (ex)" +Total (ex),Total (ex) Qty,Qty Tax,Tax -"Total (inc)","Total (inc)" -"Credit Memo # ","Credit Memo # " -"Invoice # ","Invoice # " -"The order object is not specified.","The order object is not specified." -"The source object is not specified.","The source object is not specified." -"An item object is not specified.","An item object is not specified." -"A PDF object is not specified.","A PDF object is not specified." -"A PDF page object is not specified.","A PDF page object is not specified." -"Excl. Tax","Excl. Tax" -"Incl. Tax","Incl. Tax" -"Packing Slip # ","Packing Slip # " +Total (inc),Total (inc) +Credit Memo # ,Credit Memo # +Invoice # ,Invoice # +The order object is not specified.,The order object is not specified. +The source object is not specified.,The source object is not specified. +An item object is not specified.,An item object is not specified. +A PDF object is not specified.,A PDF object is not specified. +A PDF page object is not specified.,A PDF page object is not specified. +Excl. Tax,Excl. Tax +Incl. Tax,Incl. Tax +Packing Slip # ,Packing Slip # title,title -"The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal.","The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal." -"We cannot register an existing shipment","We cannot register an existing shipment" -"Parent shipment cannot be loaded for track object.","Parent shipment cannot be loaded for track object." -"Order Id is required for shipment document","Order Id is required for shipment document" -"You can't create a shipment without products.","You can't create a shipment without products." +The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal.,The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal. +We cannot register an existing shipment,We cannot register an existing shipment +Parent shipment cannot be loaded for track object.,Parent shipment cannot be loaded for track object. +Order Id is required for shipment document,Order Id is required for shipment document +You can't create a shipment without products.,You can't create a shipment without products. "The shipment contains product SKU ""%1"" that is not part of the original order.","The shipment contains product SKU ""%1"" that is not part of the original order." "The quantity to ship must not be greater than the unshipped quantity for product SKU ""%1"".","The quantity to ship must not be greater than the unshipped quantity for product SKU ""%1""." -"Please enter a tracking number.","Please enter a tracking number." -"Could not delete shipment","Could not delete shipment" -"Could not save shipment","Could not save shipment" -"The last status can't be unassigned from its current state.","The last status can't be unassigned from its current state." +Please enter a tracking number.,Please enter a tracking number. +Could not delete shipment,Could not delete shipment +Could not save shipment,Could not save shipment +The last status can't be unassigned from its current state.,The last status can't be unassigned from its current state. "Status can't be unassigned, because it is used by existing order(s).","Status can't be unassigned, because it is used by existing order(s)." -"The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal.","The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal." -"An invoice cannot be created when an order has a status of %1","An invoice cannot be created when an order has a status of %1" -"A creditmemo can not be created when an order has a status of %1","A creditmemo can not be created when an order has a status of %1" -"The order does not allow a creditmemo to be created.","The order does not allow a creditmemo to be created." -"A shipment cannot be created when an order has a status of %1","A shipment cannot be created when an order has a status of %1" -"The order does not allow a shipment to be created.","The order does not allow a shipment to be created." +The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal.,The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal. +An invoice cannot be created when an order has a status of %1,An invoice cannot be created when an order has a status of %1 +A creditmemo can not be created when an order has a status of %1,A creditmemo can not be created when an order has a status of %1 +The order does not allow a creditmemo to be created.,The order does not allow a creditmemo to be created. +A shipment cannot be created when an order has a status of %1,A shipment cannot be created when an order has a status of %1 +The order does not allow a shipment to be created.,The order does not allow a shipment to be created. """Creditmemo Document Validation Error(s):\n"" .","""Creditmemo Document Validation Error(s):\n"" ." "Could not save a Creditmemo, see error log for details","Could not save a Creditmemo, see error log for details" -"We cannot determine the field name.","We cannot determine the field name." +We cannot determine the field name.,We cannot determine the field name. City,City Company,Company Country,Country Email,Email -"First Name","First Name" -"Last Name","Last Name" +First Name,First Name +Last Name,Last Name State/Province,State/Province -"Street Address","Street Address" -"Phone Number","Phone Number" -"Zip/Postal Code","Zip/Postal Code" -"We can't save the address:\n%1","We can't save the address:\n%1" -"Cannot save comment:\n%1","Cannot save comment:\n%1" -"We don't have enough information to save the parent transaction ID.","We don't have enough information to save the parent transaction ID." -"We cannot create an empty shipment.","We cannot create an empty shipment." -"Cannot save track:\n%1","Cannot save track:\n%1" -"Cannot unassign status from state","Cannot unassign status from state" -"New Orders","New Orders" -"Order #%1 created at %2","Order #%1 created at %2" -"Details for %1 #%2","Details for %1 #%2" -"Notified Date: %1","Notified Date: %1" -"Comment: %1<br/>","Comment: %1<br/>" -"Current Status: %1<br/>","Current Status: %1<br/>" -"Total: %1<br/>","Total: %1<br/>" -"Order # %1 Notification(s)","Order # %1 Notification(s)" -"You can not cancel Credit Memo","You can not cancel Credit Memo" -"Could not cancel creditmemo","Could not cancel creditmemo" -"We cannot register an existing credit memo.","We cannot register an existing credit memo." +Street Address,Street Address +Phone Number,Phone Number +Zip/Postal Code,Zip/Postal Code +We can't save the address:\n%1,We can't save the address:\n%1 +Cannot save comment:\n%1,Cannot save comment:\n%1 +We don't have enough information to save the parent transaction ID.,We don't have enough information to save the parent transaction ID. +We cannot create an empty shipment.,We cannot create an empty shipment. +Cannot save track:\n%1,Cannot save track:\n%1 +Cannot unassign status from state,Cannot unassign status from state +New Orders,New Orders +Order #%1 created at %2,Order #%1 created at %2 +Details for %1 #%2,Details for %1 #%2 +Notified Date: %1,Notified Date: %1 +Comment: %1<br/>,Comment: %1<br/> +Current Status: %1<br/>,Current Status: %1<br/> +Total: %1<br/>,Total: %1<br/> +Order # %1 Notification(s),Order # %1 Notification(s) +You can not cancel Credit Memo,You can not cancel Credit Memo +Could not cancel creditmemo,Could not cancel creditmemo +We cannot register an existing credit memo.,We cannot register an existing credit memo. "We found an invalid quantity to invoice item ""%1"".","We found an invalid quantity to invoice item ""%1""." "The Order State ""%1"" must not be set manually.","The Order State ""%1"" must not be set manually." """Shipment Document Validation Error(s):\n"" .","""Shipment Document Validation Error(s):\n"" ." "Could not save a shipment, see error log for details","Could not save a shipment, see error log for details" -"VAT Request Identifier","VAT Request Identifier" -"VAT Request Date","VAT Request Date" -"Pending Payment","Pending Payment" +VAT Request Identifier,VAT Request Identifier +VAT Request Date,VAT Request Date +Pending Payment,Pending Payment Processing,Processing -"On Hold","On Hold" +On Hold,On Hold Complete,Complete Closed,Closed -"Suspected Fraud","Suspected Fraud" -"Payment Review","Payment Review" +Suspected Fraud,Suspected Fraud +Payment Review,Payment Review New,New -"test message","test message" -"Email has not been sent","Email has not been sent" -"Authorized amount of %1.","Authorized amount of %1." -"We will authorize %1 after the payment is approved at the payment gateway.","We will authorize %1 after the payment is approved at the payment gateway." -"Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent.","Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent." -"Captured amount of %1 online.","Captured amount of %1 online." -"Authorized amount of %1","Authorized amount of %1" +test message,test message +Email has not been sent,Email has not been sent +Authorized amount of %1.,Authorized amount of %1. +We will authorize %1 after the payment is approved at the payment gateway.,We will authorize %1 after the payment is approved at the payment gateway. +Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent.,Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent. +Captured amount of %1 online.,Captured amount of %1 online. +Authorized amount of %1,Authorized amount of %1 " Transaction ID: ""%1"""," Transaction ID: ""%1""" View,View -"Group was removed","Group was removed" +Group was removed,Group was removed "Changing address information will not recalculate shipping, tax or other order amount.","Changing address information will not recalculate shipping, tax or other order amount." -"Comment Text","Comment Text" -"Notify Customer by Email","Notify Customer by Email" -"Visible on Storefront","Visible on Storefront" +Comment Text,Comment Text +Notify Customer by Email,Notify Customer by Email +Visible on Storefront,Visible on Storefront Customer,Customer Notified,Notified -"Not Notified","Not Notified" -"No Payment Methods","No Payment Methods" -"Order Comments","Order Comments" -"Apply Coupon Code","Apply Coupon Code" +Not Notified,Not Notified +No Payment Methods,No Payment Methods +Order Comments,Order Comments +Apply Coupon Code,Apply Coupon Code Apply,Apply -"Remove Coupon Code","Remove Coupon Code" +Remove Coupon Code,Remove Coupon Code Remove,Remove -"Address Information","Address Information" -"Payment & Shipping Information","Payment & Shipping Information" -"Order Total","Order Total" -"Order Currency:","Order Currency:" -"Same As Billing Address","Same As Billing Address" -"Select from existing customer addresses:","Select from existing customer addresses:" -"Add New Address","Add New Address" -"Save in address book","Save in address book" -"You don't need to select a shipping address.","You don't need to select a shipping address." -"Gift Message for the Entire Order","Gift Message for the Entire Order" -"Leave this box blank if you don't want to leave a gift message for the entire order.","Leave this box blank if you don't want to leave a gift message for the entire order." -"Row Subtotal","Row Subtotal" +Address Information,Address Information +Payment & Shipping Information,Payment & Shipping Information +Order Total,Order Total +Order Currency:,Order Currency: +Same As Billing Address,Same As Billing Address +Select from existing customer addresses:,Select from existing customer addresses: +Add New Address,Add New Address +Save in address book,Save in address book +You don't need to select a shipping address.,You don't need to select a shipping address. +Gift Message for the Entire Order,Gift Message for the Entire Order +Leave this box blank if you don't want to leave a gift message for the entire order.,Leave this box blank if you don't want to leave a gift message for the entire order. +Row Subtotal,Row Subtotal Action,Action -"No ordered items","No ordered items" -"Update Items and Quantities","Update Items and Quantities" -"Total %1 product(s)","Total %1 product(s)" +No ordered items,No ordered items +Update Items and Quantities,Update Items and Quantities +Total %1 product(s),Total %1 product(s) Subtotal:,Subtotal: -"Tier Pricing","Tier Pricing" -"Custom Price","Custom Price" -"Please select","Please select" -"Move to Shopping Cart","Move to Shopping Cart" -"Move to Wish List","Move to Wish List" -"Subscribe to Newsletter","Subscribe to Newsletter" -"Click to change shipping method","Click to change shipping method" +Tier Pricing,Tier Pricing +Custom Price,Custom Price +Please select,Please select +Move to Shopping Cart,Move to Shopping Cart +Move to Wish List,Move to Wish List +Subscribe to Newsletter,Subscribe to Newsletter +Click to change shipping method,Click to change shipping method "Sorry, no quotes are available for this order.","Sorry, no quotes are available for this order." -"Get shipping methods and rates","Get shipping methods and rates" -"You don't need to select a shipping method.","You don't need to select a shipping method." -"Customer's Activities","Customer's Activities" +Get shipping methods and rates,Get shipping methods and rates +You don't need to select a shipping method.,You don't need to select a shipping method. +Customer's Activities,Customer's Activities Refresh,Refresh Item,Item -"Add To Order","Add To Order" -"Configure and Add to Order","Configure and Add to Order" -"No items","No items" -"Append Comments","Append Comments" -"Email Order Confirmation","Email Order Confirmation" -"Grand Total Excl. Tax","Grand Total Excl. Tax" -"Grand Total Incl. Tax","Grand Total Incl. Tax" -"Subtotal (Excl. Tax)","Subtotal (Excl. Tax)" -"Subtotal (Incl. Tax)","Subtotal (Incl. Tax)" -"Payment & Shipping Method","Payment & Shipping Method" -"Payment Information","Payment Information" -"The order was placed using %1.","The order was placed using %1." -"Shipping Information","Shipping Information" -"Items to Refund","Items to Refund" -"Return to Stock","Return to Stock" -"Qty to Refund","Qty to Refund" -"Tax Amount","Tax Amount" -"Discount Amount","Discount Amount" -"Row Total","Row Total" -"No Items To Refund","No Items To Refund" -"Credit Memo Comments","Credit Memo Comments" -"Refund Totals","Refund Totals" -"Email Copy of Credit Memo","Email Copy of Credit Memo" -"Please enter a positive number in this field.","Please enter a positive number in this field." -"Items Refunded","Items Refunded" -"No Items","No Items" -"Memo Total","Memo Total" -"Credit Memo History","Credit Memo History" -"Credit Memo Totals","Credit Memo Totals" -"Customer Name: %1","Customer Name: %1" -"Purchased From: %1","Purchased From: %1" -"Gift Message","Gift Message" +Add To Order,Add To Order +Configure and Add to Order,Configure and Add to Order +No items,No items +Append Comments,Append Comments +Email Order Confirmation,Email Order Confirmation +Grand Total Excl. Tax,Grand Total Excl. Tax +Grand Total Incl. Tax,Grand Total Incl. Tax +Subtotal (Excl. Tax),Subtotal (Excl. Tax) +Subtotal (Incl. Tax),Subtotal (Incl. Tax) +Payment & Shipping Method,Payment & Shipping Method +Payment Information,Payment Information +The order was placed using %1.,The order was placed using %1. +Shipping Information,Shipping Information +Items to Refund,Items to Refund +Return to Stock,Return to Stock +Qty to Refund,Qty to Refund +Tax Amount,Tax Amount +Discount Amount,Discount Amount +Row Total,Row Total +No Items To Refund,No Items To Refund +Credit Memo Comments,Credit Memo Comments +Refund Totals,Refund Totals +Email Copy of Credit Memo,Email Copy of Credit Memo +Please enter a positive number in this field.,Please enter a positive number in this field. +Items Refunded,Items Refunded +No Items,No Items +Memo Total,Memo Total +Credit Memo History,Credit Memo History +Credit Memo Totals,Credit Memo Totals +Customer Name: %1,Customer Name: %1 +Purchased From: %1,Purchased From: %1 +Gift Message,Gift Message From:,From: To:,To: Message:,Message: -"Shipping & Handling","Shipping & Handling" -"Gift Options","Gift Options" -"Create Shipment","Create Shipment" -"Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice.","Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice." +Shipping & Handling,Shipping & Handling +Gift Options,Gift Options +Create Shipment,Create Shipment +Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice.,Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice. %1,%1 -"Qty to Invoice","Qty to Invoice" -"Invoice History","Invoice History" -"Invoice Comments","Invoice Comments" -"Invoice Totals","Invoice Totals" +Qty to Invoice,Qty to Invoice +Invoice History,Invoice History +Invoice Comments,Invoice Comments +Invoice Totals,Invoice Totals Amount,Amount -"Capture Online","Capture Online" -"Capture Offline","Capture Offline" -"Not Capture","Not Capture" -"The invoice will be created offline without the payment gateway.","The invoice will be created offline without the payment gateway." -"Email Copy of Invoice","Email Copy of Invoice" -"Items Invoiced","Items Invoiced" -"Total Tax","Total Tax" -"From Name","From Name" -"To Name","To Name" +Capture Online,Capture Online +Capture Offline,Capture Offline +Not Capture,Not Capture +The invoice will be created offline without the payment gateway.,The invoice will be created offline without the payment gateway. +Email Copy of Invoice,Email Copy of Invoice +Items Invoiced,Items Invoiced +Total Tax,Total Tax +From Name,From Name +To Name,To Name Status,Status Comment,Comment -"Notification Not Applicable","Notification Not Applicable" -"Order & Account Information","Order & Account Information" -"The order confirmation email was sent","The order confirmation email was sent" -"The order confirmation email is not sent","The order confirmation email is not sent" -"Order Date","Order Date" -"Order Date (%1)","Order Date (%1)" -"Purchased From","Purchased From" -"Link to the New Order","Link to the New Order" -"Link to the Previous Order","Link to the Previous Order" -"Placed from IP","Placed from IP" -"%1 / %2 rate:","%1 / %2 rate:" -"Customer Name","Customer Name" -"Customer Group","Customer Group" -"Notes for this Order","Notes for this Order" -"Comment added","Comment added" -"Transaction Data","Transaction Data" -"Transaction ID","Transaction ID" -"Parent Transaction ID","Parent Transaction ID" -"Order ID","Order ID" -"Transaction Type","Transaction Type" -"Is Closed","Is Closed" -"Created At","Created At" -"Child Transactions","Child Transactions" -"Transaction Details","Transaction Details" +Notification Not Applicable,Notification Not Applicable +Order & Account Information,Order & Account Information +The order confirmation email was sent,The order confirmation email was sent +The order confirmation email is not sent,The order confirmation email is not sent +Order Date,Order Date +Order Date (%1),Order Date (%1) +Purchased From,Purchased From +Link to the New Order,Link to the New Order +Link to the Previous Order,Link to the Previous Order +Placed from IP,Placed from IP +%1 / %2 rate:,%1 / %2 rate: +Customer Name,Customer Name +Customer Group,Customer Group +Notes for this Order,Notes for this Order +Comment added,Comment added +Transaction Data,Transaction Data +Transaction ID,Transaction ID +Parent Transaction ID,Parent Transaction ID +Order ID,Order ID +Transaction Type,Transaction Type +Is Closed,Is Closed +Created At,Created At +Child Transactions,Child Transactions +Transaction Details,Transaction Details Items,Items -"Gift Message for this Order","Gift Message for this Order" -"Shipped By","Shipped By" -"Tracking Number","Tracking Number" -"Billing Last Name","Billing Last Name" -"Find Order By","Find Order By" -"ZIP Code","ZIP Code" -"Billing ZIP Code","Billing ZIP Code" +Gift Message for this Order,Gift Message for this Order +Shipped By,Shipped By +Tracking Number,Tracking Number +Billing Last Name,Billing Last Name +Find Order By,Find Order By +ZIP Code,ZIP Code +Billing ZIP Code,Billing ZIP Code Continue,Continue -"Print All Refunds","Print All Refunds" -"Refund #","Refund #" -"Print Refund","Print Refund" -"Product Name","Product Name" -"Order #","Order #" +Print All Refunds,Print All Refunds +Refund #,Refund # +Print Refund,Print Refund +Product Name,Product Name +Order #,Order # Date,Date -"Ship To","Ship To" +Ship To,Ship To Actions,Actions -"View Order","View Order" -"You have placed no orders.","You have placed no orders." -"No shipping information available","No shipping information available" -"Print Order","Print Order" -"Print All Invoices","Print All Invoices" -"Invoice #","Invoice #" -"Print Invoice","Print Invoice" -"Qty Invoiced","Qty Invoiced" +View Order,View Order +You have placed no orders.,You have placed no orders. +No shipping information available,No shipping information available +Print Order,Print Order +Print All Invoices,Print All Invoices +Invoice #,Invoice # +Print Invoice,Print Invoice +Qty Invoiced,Qty Invoiced Close,Close -"About Your Order","About Your Order" +About Your Order,About Your Order "<span class=""label"">Order Date:</span> %1","<span class=""label"">Order Date:</span> %1" -"Refund #%1","Refund #%1" -"Shipment #%1","Shipment #%1" -"Qty Shipped","Qty Shipped" -"Recent Orders","Recent Orders" -"View All","View All" -"Gift Message for This Order","Gift Message for This Order" -"Recently Ordered","Recently Ordered" -"Add to Cart","Add to Cart" +Refund #%1,Refund #%1 +Shipment #%1,Shipment #%1 +Qty Shipped,Qty Shipped +Recent Orders,Recent Orders +View All,View All +Gift Message for This Order,Gift Message for This Order +Recently Ordered,Recently Ordered +Add to Cart,Add to Cart Search,Search -"Credit memo for your %store_name order","Credit memo for your %store_name order" +Credit memo for your %store_name order,Credit memo for your %store_name order "%name,","%name," -"Thank you for your order from %store_name.","Thank you for your order from %store_name." +Thank you for your order from %store_name.,Thank you for your order from %store_name. "You can check the status of your order by <a href=""%account_url"">logging into your account</a>.","You can check the status of your order by <a href=""%account_url"">logging into your account</a>." "If you have questions about your order, you can email us at <a href=""mailto:%store_email"">%store_email</a>","If you have questions about your order, you can email us at <a href=""mailto:%store_email"">%store_email</a>" "or call us at <a href=""tel:%store_phone"">%store_phone</a>","or call us at <a href=""tel:%store_phone"">%store_phone</a>" "Our hours are <span class=""no-link"">%store_hours</span>.","Our hours are <span class=""no-link"">%store_hours</span>." -"Your Credit Memo #%creditmemo_id for Order #%order_id","Your Credit Memo #%creditmemo_id for Order #%order_id" -"Billing Info","Billing Info" -"Shipping Info","Shipping Info" -"Update to your %store_name credit memo","Update to your %store_name credit memo" -"Your order #%increment_id has been updated with a status of <strong>%order_status</strong>.","Your order #%increment_id has been updated with a status of <strong>%order_status</strong>." -"Invoice for your %store_name order","Invoice for your %store_name order" -"Your Invoice #%invoice_id for Order #%order_id","Your Invoice #%invoice_id for Order #%order_id" -"Update to your %store_name invoice","Update to your %store_name invoice" -"Your %store_name order confirmation","Your %store_name order confirmation" +Your Credit Memo #%creditmemo_id for Order #%order_id,Your Credit Memo #%creditmemo_id for Order #%order_id +Billing Info,Billing Info +Shipping Info,Shipping Info +Update to your %store_name credit memo,Update to your %store_name credit memo +Your order #%increment_id has been updated with a status of <strong>%order_status</strong>.,Your order #%increment_id has been updated with a status of <strong>%order_status</strong>. +Invoice for your %store_name order,Invoice for your %store_name order +Your Invoice #%invoice_id for Order #%order_id,Your Invoice #%invoice_id for Order #%order_id +Update to your %store_name invoice,Update to your %store_name invoice +Your %store_name order confirmation,Your %store_name order confirmation "%customer_name,","%customer_name," -"Once your package ships we will send you a tracking number.","Once your package ships we will send you a tracking number." +Once your package ships we will send you a tracking number.,Once your package ships we will send you a tracking number. "Your Order <span class=""no-link"">#%increment_id</span>","Your Order <span class=""no-link"">#%increment_id</span>" "Placed on <span class=""no-link"">%created_at</span>","Placed on <span class=""no-link"">%created_at</span>" -"Once your package ships we will send an email with a link to track your order.","Once your package ships we will send an email with a link to track your order." -"Update to your %store_name order","Update to your %store_name order" -"Your %store_name order has shipped","Your %store_name order has shipped" -"Your shipping confirmation is below. Thank you again for your business.","Your shipping confirmation is below. Thank you again for your business." -"Your Shipment #%shipment_id for Order #%order_id","Your Shipment #%shipment_id for Order #%order_id" -"Update to your %store_name shipment","Update to your %store_name shipment" -"Gift Options for ","Gift Options for " -"Add Products","Add Products" -"You have item changes","You have item changes" +Once your package ships we will send an email with a link to track your order.,Once your package ships we will send an email with a link to track your order. +Update to your %store_name order,Update to your %store_name order +Your %store_name order has shipped,Your %store_name order has shipped +Your shipping confirmation is below. Thank you again for your business.,Your shipping confirmation is below. Thank you again for your business. +Your Shipment #%shipment_id for Order #%order_id,Your Shipment #%shipment_id for Order #%order_id +Update to your %store_name shipment,Update to your %store_name shipment +Gift Options for ,Gift Options for +Add Products,Add Products +You have item changes,You have item changes Ok,Ok Operations,Operations Create,Create -"Send Order Email","Send Order Email" -"Accept or Deny Payment","Accept or Deny Payment" -"Send Sales Emails","Send Sales Emails" -"Sales Section","Sales Section" -"Sales Emails Section","Sales Emails Section" +Send Order Email,Send Order Email +Accept or Deny Payment,Accept or Deny Payment +Send Sales Emails,Send Sales Emails +Sales Section,Sales Section +Sales Emails Section,Sales Emails Section General,General -"Hide Customer IP","Hide Customer IP" +Hide Customer IP,Hide Customer IP "Choose whether a customer IP is shown in orders, invoices, shipments, and credit memos.","Choose whether a customer IP is shown in orders, invoices, shipments, and credit memos." -"Checkout Totals Sort Order","Checkout Totals Sort Order" -"Allow Reorder","Allow Reorder" -"Invoice and Packing Slip Design","Invoice and Packing Slip Design" -"Logo for PDF Print-outs (200x50)","Logo for PDF Print-outs (200x50)" +Checkout Totals Sort Order,Checkout Totals Sort Order +Allow Reorder,Allow Reorder +Invoice and Packing Slip Design,Invoice and Packing Slip Design +Logo for PDF Print-outs (200x50),Logo for PDF Print-outs (200x50) "Your default logo will be used in PDF and HTML documents.<br />(jpeg, tiff, png) If your pdf image is distorted, try to use larger file-size image.","Your default logo will be used in PDF and HTML documents.<br />(jpeg, tiff, png) If your pdf image is distorted, try to use larger file-size image." -"Logo for HTML Print View","Logo for HTML Print View" +Logo for HTML Print View,Logo for HTML Print View "Logo for HTML documents only. If empty, default will be used.<br />(jpeg, gif, png)","Logo for HTML documents only. If empty, default will be used.<br />(jpeg, gif, png)" Address,Address -"Minimum Order Amount","Minimum Order Amount" +Minimum Order Amount,Minimum Order Amount Enable,Enable -"Minimum Amount","Minimum Amount" -"Subtotal after discount","Subtotal after discount" -"Include Tax to Amount","Include Tax to Amount" -"Description Message","Description Message" -"This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount.","This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount." -"Error to Show in Shopping Cart","Error to Show in Shopping Cart" -"Validate Each Address Separately in Multi-address Checkout","Validate Each Address Separately in Multi-address Checkout" -"Multi-address Description Message","Multi-address Description Message" -"We'll use the default description above if you leave this empty.","We'll use the default description above if you leave this empty." -"Multi-address Error to Show in Shopping Cart","Multi-address Error to Show in Shopping Cart" -"We'll use the default error above if you leave this empty.","We'll use the default error above if you leave this empty." +Minimum Amount,Minimum Amount +Subtotal after discount,Subtotal after discount +Include Tax to Amount,Include Tax to Amount +Description Message,Description Message +This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount.,This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount. +Error to Show in Shopping Cart,Error to Show in Shopping Cart +Validate Each Address Separately in Multi-address Checkout,Validate Each Address Separately in Multi-address Checkout +Multi-address Description Message,Multi-address Description Message +We'll use the default description above if you leave this empty.,We'll use the default description above if you leave this empty. +Multi-address Error to Show in Shopping Cart,Multi-address Error to Show in Shopping Cart +We'll use the default error above if you leave this empty.,We'll use the default error above if you leave this empty. Dashboard,Dashboard -"Use Aggregated Data","Use Aggregated Data" -"Orders Cron Settings","Orders Cron Settings" -"Pending Payment Order Lifetime (minutes)","Pending Payment Order Lifetime (minutes)" -"Sales Emails","Sales Emails" -"Asynchronous sending","Asynchronous sending" +Use Aggregated Data,Use Aggregated Data +Orders Cron Settings,Orders Cron Settings +Pending Payment Order Lifetime (minutes),Pending Payment Order Lifetime (minutes) +Sales Emails,Sales Emails +Asynchronous sending,Asynchronous sending Enabled,Enabled -"New Order Confirmation Email Sender","New Order Confirmation Email Sender" -"New Order Confirmation Template","New Order Confirmation Template" +New Order Confirmation Email Sender,New Order Confirmation Email Sender +New Order Confirmation Template,New Order Confirmation Template "Email template chosen based on theme fallback when ""Default"" option is selected.","Email template chosen based on theme fallback when ""Default"" option is selected." -"New Order Confirmation Template for Guest","New Order Confirmation Template for Guest" -"Send Order Email Copy To","Send Order Email Copy To" +New Order Confirmation Template for Guest,New Order Confirmation Template for Guest +Send Order Email Copy To,Send Order Email Copy To Comma-separated,Comma-separated -"Send Order Email Copy Method","Send Order Email Copy Method" -"Order Comment Email Sender","Order Comment Email Sender" -"Order Comment Email Template","Order Comment Email Template" -"Order Comment Email Template for Guest","Order Comment Email Template for Guest" -"Send Order Comment Email Copy To","Send Order Comment Email Copy To" -"Send Order Comments Email Copy Method","Send Order Comments Email Copy Method" -"Invoice Email Sender","Invoice Email Sender" -"Invoice Email Template","Invoice Email Template" -"Invoice Email Template for Guest","Invoice Email Template for Guest" -"Send Invoice Email Copy To","Send Invoice Email Copy To" -"Send Invoice Email Copy Method","Send Invoice Email Copy Method" -"Invoice Comment Email Sender","Invoice Comment Email Sender" -"Invoice Comment Email Template","Invoice Comment Email Template" -"Invoice Comment Email Template for Guest","Invoice Comment Email Template for Guest" -"Send Invoice Comment Email Copy To","Send Invoice Comment Email Copy To" -"Send Invoice Comments Email Copy Method","Send Invoice Comments Email Copy Method" +Send Order Email Copy Method,Send Order Email Copy Method +Order Comment Email Sender,Order Comment Email Sender +Order Comment Email Template,Order Comment Email Template +Order Comment Email Template for Guest,Order Comment Email Template for Guest +Send Order Comment Email Copy To,Send Order Comment Email Copy To +Send Order Comments Email Copy Method,Send Order Comments Email Copy Method +Invoice Email Sender,Invoice Email Sender +Invoice Email Template,Invoice Email Template +Invoice Email Template for Guest,Invoice Email Template for Guest +Send Invoice Email Copy To,Send Invoice Email Copy To +Send Invoice Email Copy Method,Send Invoice Email Copy Method +Invoice Comment Email Sender,Invoice Comment Email Sender +Invoice Comment Email Template,Invoice Comment Email Template +Invoice Comment Email Template for Guest,Invoice Comment Email Template for Guest +Send Invoice Comment Email Copy To,Send Invoice Comment Email Copy To +Send Invoice Comments Email Copy Method,Send Invoice Comments Email Copy Method Shipment,Shipment -"Shipment Email Sender","Shipment Email Sender" -"Shipment Email Template","Shipment Email Template" -"Shipment Email Template for Guest","Shipment Email Template for Guest" -"Send Shipment Email Copy To","Send Shipment Email Copy To" -"Send Shipment Email Copy Method","Send Shipment Email Copy Method" -"Shipment Comments","Shipment Comments" -"Shipment Comment Email Sender","Shipment Comment Email Sender" -"Shipment Comment Email Template","Shipment Comment Email Template" -"Shipment Comment Email Template for Guest","Shipment Comment Email Template for Guest" -"Send Shipment Comment Email Copy To","Send Shipment Comment Email Copy To" -"Send Shipment Comments Email Copy Method","Send Shipment Comments Email Copy Method" -"Credit Memo Email Sender","Credit Memo Email Sender" -"Credit Memo Email Template","Credit Memo Email Template" -"Credit Memo Email Template for Guest","Credit Memo Email Template for Guest" -"Send Credit Memo Email Copy To","Send Credit Memo Email Copy To" -"Send Credit Memo Email Copy Method","Send Credit Memo Email Copy Method" -"Credit Memo Comment Email Sender","Credit Memo Comment Email Sender" -"Credit Memo Comment Email Template","Credit Memo Comment Email Template" -"Credit Memo Comment Email Template for Guest","Credit Memo Comment Email Template for Guest" -"Send Credit Memo Comment Email Copy To","Send Credit Memo Comment Email Copy To" -"Send Credit Memo Comments Email Copy Method","Send Credit Memo Comments Email Copy Method" -"PDF Print-outs","PDF Print-outs" -"Display Order ID in Header","Display Order ID in Header" -"Customer Order Status Notification","Customer Order Status Notification" -"Asynchronous indexing","Asynchronous indexing" -"Orders and Returns Search Form","Orders and Returns Search Form" -"Anchor Custom Title","Anchor Custom Title" +Shipment Email Sender,Shipment Email Sender +Shipment Email Template,Shipment Email Template +Shipment Email Template for Guest,Shipment Email Template for Guest +Send Shipment Email Copy To,Send Shipment Email Copy To +Send Shipment Email Copy Method,Send Shipment Email Copy Method +Shipment Comments,Shipment Comments +Shipment Comment Email Sender,Shipment Comment Email Sender +Shipment Comment Email Template,Shipment Comment Email Template +Shipment Comment Email Template for Guest,Shipment Comment Email Template for Guest +Send Shipment Comment Email Copy To,Send Shipment Comment Email Copy To +Send Shipment Comments Email Copy Method,Send Shipment Comments Email Copy Method +Credit Memo Email Sender,Credit Memo Email Sender +Credit Memo Email Template,Credit Memo Email Template +Credit Memo Email Template for Guest,Credit Memo Email Template for Guest +Send Credit Memo Email Copy To,Send Credit Memo Email Copy To +Send Credit Memo Email Copy Method,Send Credit Memo Email Copy Method +Credit Memo Comment Email Sender,Credit Memo Comment Email Sender +Credit Memo Comment Email Template,Credit Memo Comment Email Template +Credit Memo Comment Email Template for Guest,Credit Memo Comment Email Template for Guest +Send Credit Memo Comment Email Copy To,Send Credit Memo Comment Email Copy To +Send Credit Memo Comments Email Copy Method,Send Credit Memo Comments Email Copy Method +PDF Print-outs,PDF Print-outs +Display Order ID in Header,Display Order ID in Header +Customer Order Status Notification,Customer Order Status Notification +Asynchronous indexing,Asynchronous indexing +Orders and Returns Search Form,Orders and Returns Search Form +Anchor Custom Title,Anchor Custom Title Template,Template -"Default Template","Default Template" +Default Template,Default Template Name,Name Phone,Phone -"ZIP/Post Code","ZIP/Post Code" -"Signed-up Point","Signed-up Point" +ZIP/Post Code,ZIP/Post Code +Signed-up Point,Signed-up Point Website,Website -"Bill-to Name","Bill-to Name" +Bill-to Name,Bill-to Name Created,Created -"Invoice Date","Invoice Date" -"Ship-to Name","Ship-to Name" -"Ship Date","Ship Date" -"Total Quantity","Total Quantity" -"Default Status","Default Status" -"State Code and Title","State Code and Title" -"Item Status","Item Status" -"Original Price","Original Price" -"Tax Percent","Tax Percent" -"All Store Views","All Store Views" -"PDF Credit Memos","PDF Credit Memos" -"Purchase Point","Purchase Point" -"Print Invoices","Print Invoices" -"Print Packing Slips","Print Packing Slips" -"Print Credit Memos","Print Credit Memos" -"Print All","Print All" -"Print Shipping Labels","Print Shipping Labels" -"Purchase Date","Purchase Date" -"Grand Total (Base)","Grand Total (Base)" -"Grand Total (Purchased)","Grand Total (Purchased)" -"Customer Email","Customer Email" -"Shipping and Handling","Shipping and Handling" -"PDF Invoices","PDF Invoices" -"PDF Shipments","PDF Shipments" -"PDF Creditmemos","PDF Creditmemos" +Invoice Date,Invoice Date +Ship-to Name,Ship-to Name +Ship Date,Ship Date +Total Quantity,Total Quantity +Default Status,Default Status +State Code and Title,State Code and Title +Item Status,Item Status +Original Price,Original Price +Tax Percent,Tax Percent +All Store Views,All Store Views +PDF Credit Memos,PDF Credit Memos +Purchase Point,Purchase Point +Print Invoices,Print Invoices +Print Packing Slips,Print Packing Slips +Print Credit Memos,Print Credit Memos +Print All,Print All +Print Shipping Labels,Print Shipping Labels +Purchase Date,Purchase Date +Grand Total (Base),Grand Total (Base) +Grand Total (Purchased),Grand Total (Purchased) +Customer Email,Customer Email +Shipping and Handling,Shipping and Handling +PDF Invoices,PDF Invoices +PDF Shipments,PDF Shipments +PDF Creditmemos,PDF Creditmemos Refunds,Refunds -"Allow Zero GrandTotal for Creditmemo","Allow Zero GrandTotal for Creditmemo" -"Allow Zero GrandTotal","Allow Zero GrandTotal" +Allow Zero GrandTotal for Creditmemo,Allow Zero GrandTotal for Creditmemo +Allow Zero GrandTotal,Allow Zero GrandTotal Email is required field for Admin order creation,Email is required field for Admin order creation If set YES Email field will be required during Admin order creation for new Customer.,If set YES Email field will be required during Admin order creation for new Customer. -"Could not save the shipment tracking","Could not save the shipment tracking" -"Please enter a coupon code!","Please enter a coupon code!" -"Reorder is not available.","Reorder is not available." +Could not save the shipment tracking,Could not save the shipment tracking +Please enter a coupon code!,Please enter a coupon code! +Reorder is not available.,Reorder is not available. +This creditmemo no longer exists.,This creditmemo no longer exists. diff --git a/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml index 09f74839b3a30..14587e17f75ba 100644 --- a/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml +++ b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminGoToShipmentViewActionGroup.xml @@ -19,4 +19,4 @@ <amOnPage url="{{AdminShipmentViewPage.url}}/{{identifier}}" stepKey="amOnShipmentViewPage"/> <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> -</actionGroups> \ No newline at end of file +</actionGroups> diff --git a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml index 5a965db2b4efe..e78a4d5b2701c 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentViewPage.xml @@ -10,4 +10,4 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="AdminShipmentViewPage" url="sales/shipment/view/shipment_id" area="admin" module="Shipping"> </page> -</pages> \ No newline at end of file +</pages> diff --git a/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml index 0311ebc320b59..13688afd0efe9 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml @@ -36,4 +36,4 @@ <see selector="{{AdminMessagesSection.error}}" userInput='This shipment no longer exists.' stepKey="seeErrorMessage"/> </test> -</tests> \ No newline at end of file +</tests> diff --git a/app/code/Magento/Shipping/i18n/en_US.csv b/app/code/Magento/Shipping/i18n/en_US.csv index f777e64ef98c9..831c361382490 100644 --- a/app/code/Magento/Shipping/i18n/en_US.csv +++ b/app/code/Magento/Shipping/i18n/en_US.csv @@ -1,179 +1,180 @@ -"New Shipment for Order #%1","New Shipment for Order #%1" -"Submit Shipment","Submit Shipment" -"You are trying to add a quantity for some products that doesn't match the quantity that was shipped.","You are trying to add a quantity for some products that doesn't match the quantity that was shipped." -"Products should be added to package(s)","Products should be added to package(s)" -"The value that you entered is not valid.","The value that you entered is not valid." -"Add Tracking Number","Add Tracking Number" -"Custom Value","Custom Value" +New Shipment for Order #%1,New Shipment for Order #%1 +Submit Shipment,Submit Shipment +You are trying to add a quantity for some products that doesn't match the quantity that was shipped.,You are trying to add a quantity for some products that doesn't match the quantity that was shipped. +Products should be added to package(s),Products should be added to package(s) +The value that you entered is not valid.,The value that you entered is not valid. +Add Tracking Number,Add Tracking Number +Custom Value,Custom Value Add,Add -"Send Tracking Information","Send Tracking Information" -"Are you sure you want to send a Shipment email to customer?","Are you sure you want to send a Shipment email to customer?" +Send Tracking Information,Send Tracking Information +Are you sure you want to send a Shipment email to customer?,Are you sure you want to send a Shipment email to customer? Print,Print -"the shipment email was sent","the shipment email was sent" -"the shipment email is not sent","the shipment email is not sent" -"Shipment #%1 | %3 (%2)","Shipment #%1 | %3 (%2)" -"Create Shipping Label...","Create Shipping Label..." -"Print Shipping Label","Print Shipping Label" -"Show Packages","Show Packages" -"About Your Shipment","About Your Shipment" -"Order # %1","Order # %1" -"Back to My Orders","Back to My Orders" -"View Another Order","View Another Order" -"Please enter a comment.","Please enter a comment." -"Cannot add new comment.","Cannot add new comment." -"Please specify a carrier.","Please specify a carrier." -"Please enter a tracking number.","Please enter a tracking number." +the shipment email was sent,the shipment email was sent +the shipment email is not sent,the shipment email is not sent +Shipment #%1 | %3 (%2),Shipment #%1 | %3 (%2) +Create Shipping Label...,Create Shipping Label... +Print Shipping Label,Print Shipping Label +Show Packages,Show Packages +About Your Shipment,About Your Shipment +Order # %1,Order # %1 +Back to My Orders,Back to My Orders +View Another Order,View Another Order +Please enter a comment.,Please enter a comment. +Cannot add new comment.,Cannot add new comment. +Please specify a carrier.,Please specify a carrier. +Please enter a tracking number.,Please enter a tracking number. Shipments,Shipments -"We can't initialize shipment for adding tracking number.","We can't initialize shipment for adding tracking number." -"Cannot add tracking number.","Cannot add tracking number." -"You created the shipping label.","You created the shipping label." -"An error occurred while creating shipping label.","An error occurred while creating shipping label." -"You sent the shipment.","You sent the shipment." -"Cannot send shipment information.","Cannot send shipment information." -"There are no shipping labels related to selected orders.","There are no shipping labels related to selected orders." -"New Shipment","New Shipment" -"We don't recognize or support the file extension in this shipment: %1.","We don't recognize or support the file extension in this shipment: %1." -"We can't initialize shipment for delete tracking number.","We can't initialize shipment for delete tracking number." -"We can't delete tracking number.","We can't delete tracking number." -"We can't load track with retrieving identifier right now.","We can't load track with retrieving identifier right now." -"We can't save the shipment right now.","We can't save the shipment right now." +We can't initialize shipment for adding tracking number.,We can't initialize shipment for adding tracking number. +Cannot add tracking number.,Cannot add tracking number. +You created the shipping label.,You created the shipping label. +An error occurred while creating shipping label.,An error occurred while creating shipping label. +You sent the shipment.,You sent the shipment. +Cannot send shipment information.,Cannot send shipment information. +There are no shipping labels related to selected orders.,There are no shipping labels related to selected orders. +New Shipment,New Shipment +We don't recognize or support the file extension in this shipment: %1.,We don't recognize or support the file extension in this shipment: %1. +We can't initialize shipment for delete tracking number.,We can't initialize shipment for delete tracking number. +We can't delete tracking number.,We can't delete tracking number. +We can't load track with retrieving identifier right now.,We can't load track with retrieving identifier right now. +We can't save the shipment right now.,We can't save the shipment right now. """Shipment Document Validation Error(s):\n"" .","""Shipment Document Validation Error(s):\n"" ." -"The shipment has been created.","The shipment has been created." -"Cannot save shipment.","Cannot save shipment." -"The order no longer exists.","The order no longer exists." -"Cannot do shipment for the order separately from invoice.","Cannot do shipment for the order separately from invoice." -"Cannot do shipment for the order.","Cannot do shipment for the order." -"There are no shipping labels related to selected shipments.","There are no shipping labels related to selected shipments." -"Page not found.","Page not found." -"Tracking Information","Tracking Information" +The shipment has been created.,The shipment has been created. +Cannot save shipment.,Cannot save shipment. +The order no longer exists.,The order no longer exists. +Cannot do shipment for the order separately from invoice.,Cannot do shipment for the order separately from invoice. +Cannot do shipment for the order.,Cannot do shipment for the order. +There are no shipping labels related to selected shipments.,There are no shipping labels related to selected shipments. +Page not found.,Page not found. +Tracking Information,Tracking Information "Sorry, but we can't deliver to the destination country with this shipping module.","Sorry, but we can't deliver to the destination country with this shipping module." -"The shipping module is not available.","The shipping module is not available." -"This shipping method is not available. Please specify the zip code.","This shipping method is not available. Please specify the zip code." -"No packages for request","No packages for request" -"Security validation of XML document has been failed.","Security validation of XML document has been failed." -"All Allowed Countries","All Allowed Countries" -"Specific Countries","Specific Countries" +The shipping module is not available.,The shipping module is not available. +This shipping method is not available. Please specify the zip code.,This shipping method is not available. Please specify the zip code. +No packages for request,No packages for request +Security validation of XML document has been failed.,Security validation of XML document has been failed. +All Allowed Countries,All Allowed Countries +Specific Countries,Specific Countries Development,Development Live,Live -"Divide to equal weight (one request)","Divide to equal weight (one request)" -"Use origin weight (few requests)","Use origin weight (few requests)" +Divide to equal weight (one request),Divide to equal weight (one request) +Use origin weight (few requests),Use origin weight (few requests) Packages,Packages Package,Package Type,Type Length,Length -"Signature Confirmation","Signature Confirmation" -"Customs Value","Customs Value" +Signature Confirmation,Signature Confirmation +Customs Value,Customs Value Width,Width Contents,Contents -"Total Weight","Total Weight" +Total Weight,Total Weight Height,Height Size,Size Girth,Girth -"Items in the Package","Items in the Package" +Items in the Package,Items in the Package Product,Product Weight,Weight -"Qty Ordered","Qty Ordered" +Qty Ordered,Qty Ordered Qty,Qty "No detail for number ""%1""","No detail for number ""%1""" -"Shipping labels is not available.","Shipping labels is not available." -"Response info is not exist.","Response info is not exist." -"Invalid carrier: %1","Invalid carrier: %1" -"We don't have enough information to create shipping labels. Please make sure your store information and settings are complete.","We don't have enough information to create shipping labels. Please make sure your store information and settings are complete." -"Per Order","Per Order" -"Per Package","Per Package" +Shipping labels is not available.,Shipping labels is not available. +Response info is not exist.,Response info is not exist. +Invalid carrier: %1,Invalid carrier: %1 +We don't have enough information to create shipping labels. Please make sure your store information and settings are complete.,We don't have enough information to create shipping labels. Please make sure your store information and settings are complete. +Per Order,Per Order +Per Package,Per Package Fixed,Fixed Percent,Percent -"Tracking information is unavailable.","Tracking information is unavailable." +Tracking information is unavailable.,Tracking information is unavailable. message,message -"Email has not been sent","Email has not been sent" -"Payment & Shipping Method","Payment & Shipping Method" -"Payment Information","Payment Information" -"The order was placed using %1.","The order was placed using %1." -"Shipping Information","Shipping Information" -"Total Shipping Charges","Total Shipping Charges" -"Incl. Tax","Incl. Tax" -"Items to Ship","Items to Ship" -"Qty to Ship","Qty to Ship" +Email has not been sent,Email has not been sent +Payment & Shipping Method,Payment & Shipping Method +Payment Information,Payment Information +The order was placed using %1.,The order was placed using %1. +Shipping Information,Shipping Information +Total Shipping Charges,Total Shipping Charges +Incl. Tax,Incl. Tax +Items to Ship,Items to Ship +Qty to Ship,Qty to Ship Ship,Ship -"Shipment Total","Shipment Total" -"Shipment Comments","Shipment Comments" -"Comment Text","Comment Text" -"Shipment Options","Shipment Options" -"Create Shipping Label","Create Shipping Label" -"Append Comments","Append Comments" -"Email Copy of Shipment","Email Copy of Shipment" -"Invalid value(s) for Qty to Ship","Invalid value(s) for Qty to Ship" -"Select All","Select All" -"Product Name","Product Name" +Shipment Total,Shipment Total +Shipment Comments,Shipment Comments +Comment Text,Comment Text +Shipment Options,Shipment Options +Create Shipping Label,Create Shipping Label +Append Comments,Append Comments +Email Copy of Shipment,Email Copy of Shipment +Invalid value(s) for Qty to Ship,Invalid value(s) for Qty to Ship +Select All,Select All +Product Name,Product Name Delete,Delete -"Create Packages","Create Packages" +Create Packages,Create Packages Cancel,Cancel Save,Save -"Add Package","Add Package" -"Add Selected Product(s) to Package","Add Selected Product(s) to Package" -"Add Products to Package","Add Products to Package" -"USPS domestic shipments don't use package types.","USPS domestic shipments don't use package types." +Add Package,Add Package +Add Selected Product(s) to Package,Add Selected Product(s) to Package +Add Products to Package,Add Products to Package +USPS domestic shipments don't use package types.,USPS domestic shipments don't use package types. in,in cm,cm lb,lb kg,kg -"Delete Package","Delete Package" +Delete Package,Delete Package Explanation,Explanation Carrier,Carrier Title,Title Number,Number Action,Action -"Are you sure?","Are you sure?" -"Shipping & Handling Information","Shipping & Handling Information" -"Track Order","Track Order" -"No shipping information available","No shipping information available" -"Shipping and Tracking Information","Shipping and Tracking Information" -"Track this shipment","Track this shipment" -"Items Shipped","Items Shipped" -"Order Total","Order Total" -"Shipment History","Shipment History" -"Qty Shipped","Qty Shipped" -"Print All Shipments","Print All Shipments" -"Shipment #","Shipment #" -"Print Shipment","Print Shipment" -"Tracking Number(s):","Tracking Number(s):" +Are you sure?,Are you sure? +Shipping & Handling Information,Shipping & Handling Information +Track Order,Track Order +No shipping information available,No shipping information available +Shipping and Tracking Information,Shipping and Tracking Information +Track this shipment,Track this shipment +Items Shipped,Items Shipped +Order Total,Order Total +Shipment History,Shipment History +Qty Shipped,Qty Shipped +Print All Shipments,Print All Shipments +Shipment #,Shipment # +Print Shipment,Print Shipment +Tracking Number(s):,Tracking Number(s): SKU,SKU -"Order tracking","Order tracking" -"Tracking Number:","Tracking Number:" +Order tracking,Order tracking +Tracking Number:,Tracking Number: Carrier:,Carrier: Error:,Error: -"Tracking information is currently not available. Please ","Tracking information is currently not available. Please " -"contact us","contact us" -" for more information or "," for more information or " -"email us at ","email us at " +Tracking information is currently not available. Please ,Tracking information is currently not available. Please +contact us,contact us + for more information or , for more information or +email us at ,email us at Info:,Info: Track:,Track: -". ':'",". ':'" -"Delivered on:","Delivered on:" +. ':',. ':' +Delivered on:,Delivered on: N/A,N/A -"There is no tracking available for this shipment.","There is no tracking available for this shipment." -"There is no tracking available.","There is no tracking available." -"Close Window","Close Window" -"Track history","Track history" +There is no tracking available for this shipment.,There is no tracking available for this shipment. +There is no tracking available.,There is no tracking available. +Close Window,Close Window +Track history,Track history Location,Location Date,Date -"Local Time","Local Time" +Local Time,Local Time Description,Description -"See our Shipping Policy","See our Shipping Policy" -"Shipping Settings Section","Shipping Settings Section" -"Shipping Policy Parameters Section","Shipping Policy Parameters Section" -"Shipping Methods Section","Shipping Methods Section" -"Shipping Settings","Shipping Settings" +See our Shipping Policy,See our Shipping Policy +Shipping Settings Section,Shipping Settings Section +Shipping Policy Parameters Section,Shipping Policy Parameters Section +Shipping Methods Section,Shipping Methods Section +Shipping Settings,Shipping Settings Origin,Origin Country,Country Region/State,Region/State -"ZIP/Postal Code","ZIP/Postal Code" +ZIP/Postal Code,ZIP/Postal Code City,City -"Street Address","Street Address" -"Street Address Line 2","Street Address Line 2" -"Shipping Policy Parameters","Shipping Policy Parameters" -"Apply custom Shipping Policy","Apply custom Shipping Policy" -"Shipping Policy","Shipping Policy" -"Shipping Methods","Shipping Methods" -"Track your order","Track your order" -"Track All Shipments","Track All Shipments" +Street Address,Street Address +Street Address Line 2,Street Address Line 2 +Shipping Policy Parameters,Shipping Policy Parameters +Apply custom Shipping Policy,Apply custom Shipping Policy +Shipping Policy,Shipping Policy +Shipping Methods,Shipping Methods +Track your order,Track your order +Track All Shipments,Track All Shipments +This shipment no longer exists.,This shipment no longer exists. From 4ba689a035c8aba55e6dc4d8c9cb48871db5d47f Mon Sep 17 00:00:00 2001 From: govindasharma974 <govindpokhrelsharma@cedcommerce.com> Date: Wed, 14 Oct 2020 11:04:51 +0530 Subject: [PATCH 016/346] Fixed some test case issues --- .../Sales/Controller/Adminhtml/Order/CreditmemoLoader.php | 2 +- .../AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml | 2 +- .../Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php index 7bb0b38a8d5ff..2451b76a5de1a 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php @@ -183,7 +183,7 @@ public function load() if ($creditmemoId) { try { $creditmemo = $this->creditmemoRepository->get($creditmemoId); - } catch (\Exception $e) { + } catch (\Exception $e) { $this->messageManager->addErrorMessage(__('This creditmemo no longer exists.')); return false; } diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml index c6522cb22cdf3..696a9f0db2eb0 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml @@ -31,7 +31,7 @@ <waitForPageLoad stepKey="waitForPageLoad"/> - <seeInCurrentUrl url="{{AdminCreditmemosGridPage.url}}" stepKey="redirectToCreditmemosGridPage"/> + <seeInCurrentUrl url="{{AdminCreditMemosGridPage.url}}" stepKey="redirectToCreditMemosGridPage"/> <see selector="{{AdminMessagesSection.error}}" userInput='This creditmemo no longer exists.' stepKey="seeErrorMessage"/> diff --git a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php index d99ce83d91de2..aa983aa5c86ce 100644 --- a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php +++ b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/Shipment/ViewTest.php @@ -87,7 +87,6 @@ class ViewTest extends TestCase */ protected $pageTitleMock; - /** * @var \Magento\Shipping\Controller\Adminhtml\Order\Shipment\View * @var RedirectFactory|MockObject @@ -104,7 +103,6 @@ class ViewTest extends TestCase */ protected $controller; - protected function setUp(): void { $this->requestMock = $this->getMockBuilder(RequestInterface::class) From 9e99f43aeca1692343abf7450b61c91b2428b95f Mon Sep 17 00:00:00 2001 From: govindasharma974 <govindpokhrelsharma@cedcommerce.com> Date: Wed, 14 Oct 2020 16:21:52 +0530 Subject: [PATCH 017/346] Fixed MFTF issue --- .../Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml index 041ebc7baa84d..d417a6c5ed314 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml @@ -16,7 +16,7 @@ <argument name="identifier" type="string"/> </arguments> - <amOnPage url="{{AdminCreditmemoViewPage.url}}/{{identifier}}" stepKey="amOnCreditmemoViewPage"/> + <amOnPage url="{{AdminCreditMemoViewPage.url}}/{{identifier}}" stepKey="amOnCreditmemoViewPage"/> <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> </actionGroups> From 87be948915016ff3398a3eec9af903cfd4dbc844 Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Thu, 22 Oct 2020 02:07:59 +0530 Subject: [PATCH 018/346] Converted TEST into automic groups for reusable actions --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 ------------------- ...minCreateWidgetWthoutLayoutActionGroup.xml | 26 +++++++++++++ .../AdminWidgetAddLayoutUpdateActionGroup.xml | 18 +++++++++ ...minWidgetDeleteLayoutUpdateActionGroup.xml | 17 +++++++++ .../Mftf/Section/AdminNewWidgetSection.xml | 4 +- ...AddAndDeleteMultipleLayoutSectionsTest.xml | 11 +++++- .../View/Helper/SecureHtmlRenderer.php | 2 +- 7 files changed, 73 insertions(+), 43 deletions(-) delete mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml deleted file mode 100644 index b7ebd09c2fcc6..0000000000000 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<actionGroups - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup"> - <annotations> - <description>Goes to the Admin Widget creation page. Add and delete multiple layouts</description> - </annotations> - <arguments> - <argument name="widget"/> - </arguments> - <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> - <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> - <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> - <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> - <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> - <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> - <waitForAjaxLoad stepKey="waitForLoad"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate2"/> - <waitForAjaxLoad stepKey="waitForLoad2"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate3"/> - <waitForAjaxLoad stepKey="waitForLoad3"/> - <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionThird}}" stepKey="clickThirdDeleteButton"/> - <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionSecond}}" stepKey="clickSecondDeleteButton"/> - <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionFirst}}" stepKey="clickFirstDeleteButton"/> - <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml new file mode 100644 index 0000000000000..e9ee80c1a5f2a --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateWidgetWthoutLayoutActionGroup"> + <annotations> + <description>Goes to the Admin Widget creation page without saving it</description> + </annotations> + <arguments> + <argument name="widget"/> + </arguments> + <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> + <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> + <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> + <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> + <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> + <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml new file mode 100644 index 0000000000000..fa73fa4926e10 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminWidgetAddLayoutUpdateActionGroup"> + <annotations> + <description>Add layouts during widgets creation</description> + </annotations> + <waitForAjaxLoad stepKey="waitForLoad"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml new file mode 100644 index 0000000000000..e52fb1a7f6514 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminWidgetDeleteLayoutUpdateActionGroup"> + <annotations> + <description>Delete layouts during widgets creation</description> + </annotations> + <click selector="{{AdminNewWidgetSection.deleteWidgetLayoutAction}}" stepKey="clickFirstDeleteButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 373274aef8584..ea2a858c63885 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -40,9 +40,7 @@ <element name="displayMode" type="select" selector="select[id*='display_mode']"/> <element name="restrictTypes" type="select" selector="select[id*='types']"/> <element name="saveAndContinue" type="button" selector="#save_and_edit_button" timeout="30"/> - <element name="deleteActionFirst" type="button" selector="#page_group_container_0 > div.fieldset-wrapper-title > div > .action-default.action-delete"/> - <element name="deleteActionSecond" type="button" selector="#page_group_container_1 > div.fieldset-wrapper-title > div > .action-default.action-delete"/> - <element name="deleteActionThird" type="button" selector="#page_group_container_2 > div.fieldset-wrapper-title > div > .action-default.action-delete"/> + <element name="deleteWidgetLayoutAction" type="button" selector="#page_group_container > div:first-of-type > div.fieldset-wrapper-title > div > .action-default.action-delete"/> <element name="CountDeleteButtons" type="button" selector="#page_group_container > .fieldset-wrapper.page_group_container > div.fieldset-wrapper-title > div > .action-default.action-delete"/> </section> </sections> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml index 5a5652e1e9049..eee6058836f2e 100644 --- a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml @@ -29,8 +29,17 @@ <argument name="title" value="{{AdminMenuContentElementsWidgets.pageTitle}}"/> </actionGroup> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> - <actionGroup ref="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup" stepKey="addWidgetForTest"> + <actionGroup ref="AdminCreateWidgetWthoutLayoutActionGroup" stepKey="addWidgetForTest"> <argument name="widget" value="ProductsListWidget"/> </actionGroup> + <actionGroup ref="AdminWidgetAddLayoutUpdateActionGroup" stepKey="AddSecondLayout"/> + <actionGroup ref="AdminWidgetAddLayoutUpdateActionGroup" stepKey="AddThirdLayout"/> + <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteFirstLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteSecondLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteThirdLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> </test> </tests> diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index ebc4b8870538f..87d4e88295356 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -112,7 +112,7 @@ function {$listenerFunction} () { {$attributeJavascript}; } var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); - if({$elementName}Array.lenght !== 'undefined'){ + if({$elementName}Array.length !== 'undefined'){ {$elementName}Array.forEach(function(element){ if (element) { element.{$eventName} = function (event) { From 9f9d2cbf492634a89cb97326fba68a02d9e7c175 Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Fri, 11 Sep 2020 11:01:41 +0530 Subject: [PATCH 019/346] Fixed issue when using dynamic elements --- .../View/Helper/SecureHtmlRenderer.php | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index ae8ab3f15bc96..d7369416f44bf 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -111,16 +111,21 @@ public function renderEventListenerAsTag( function {$listenerFunction} () { {$attributeJavascript}; } - var {$elementName} = document.querySelector("{$elementSelector}"); - if ({$elementName}) { - {$elementName}.{$eventName} = function (event) { - var targetElement = {$elementName}; - if (event && event.target) { - targetElement = event.target; + var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); + + {$elementName}Array.forEach(function(element){ + if (element) { + element.{$eventName} = function (event) { + var targetElement = element; + if (event && event.target) { + targetElement = event.target; + } + {$listenerFunction}.apply(targetElement); } - {$listenerFunction}.apply(targetElement); } - } + }); + + script; return $this->renderTag('script', ['type' => 'text/javascript'], $script, false); From 89d3814530f20248a32b678fd9636bd990a5f9fb Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Sat, 12 Sep 2020 20:06:59 +0530 Subject: [PATCH 020/346] Updated code for validate empty nodeList and covered MFTF --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 +++++++++++++++++++ .../Mftf/Section/AdminNewWidgetSection.xml | 2 + ...AddAndDeleteMultipleLayoutSectionsTest.xml | 36 ++++++++++++++++++ .../View/Helper/SecureHtmlRenderer.php | 22 +++++------ 4 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml new file mode 100644 index 0000000000000..b7ebd09c2fcc6 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup"> + <annotations> + <description>Goes to the Admin Widget creation page. Add and delete multiple layouts</description> + </annotations> + <arguments> + <argument name="widget"/> + </arguments> + <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> + <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> + <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> + <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> + <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> + <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + <waitForAjaxLoad stepKey="waitForLoad"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate2"/> + <waitForAjaxLoad stepKey="waitForLoad2"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate3"/> + <waitForAjaxLoad stepKey="waitForLoad3"/> + <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> + <click selector="{{AdminNewWidgetSection.deleteActionThird}}" stepKey="clickThirdDeleteButton"/> + <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> + <click selector="{{AdminNewWidgetSection.deleteActionSecond}}" stepKey="clickSecondDeleteButton"/> + <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> + <click selector="{{AdminNewWidgetSection.deleteActionFirst}}" stepKey="clickFirstDeleteButton"/> + <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 4064f8eb394ca..d6b1601854683 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -49,6 +49,8 @@ <element name="displayPageControl" type="select" selector="[name='parameters[show_pager]']"/> <element name="numberOfProductsToDisplay" type="input" selector="[name='parameters[products_count]']"/> <element name="cacheLifetime" type="input" selector="[name='parameters[cache_lifetime]']"/> + <element name="deleteWidgetLayoutAction" type="button" selector="#page_group_container > div:first-of-type > div.fieldset-wrapper-title > div > .action-default.action-delete"/> + <element name="CountDeleteButtons" type="button" selector="#page_group_container > .fieldset-wrapper.page_group_container > div.fieldset-wrapper-title > div > .action-default.action-delete"/> </section> </sections> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml new file mode 100644 index 0000000000000..5a5652e1e9049 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminWidgetAddAndDeleteMultipleLayoutSectionsTest"> + <annotations> + <features value="Widget"/> + <stories value="Add and Delete multiple layouts when creating a Widget"/> + <title value="Add and Delete multiple layouts"/> + <description value="Admin should be able to Add and Delete multiple layouts"/> + <severity value="CRITICAL"/> + <group value="Widget"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToContentWidgetsPageFirst"> + <argument name="menuUiId" value="{{AdminMenuContent.dataUiId}}"/> + <argument name="submenuUiId" value="{{AdminMenuContentElementsWidgets.dataUiId}}"/> + </actionGroup> + <actionGroup ref="AdminAssertPageTitleActionGroup" stepKey="seePageTitleFirst"> + <argument name="title" value="{{AdminMenuContentElementsWidgets.pageTitle}}"/> + </actionGroup> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> + <actionGroup ref="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup" stepKey="addWidgetForTest"> + <argument name="widget" value="ProductsListWidget"/> + </actionGroup> + </test> +</tests> diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index d7369416f44bf..ebc4b8870538f 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -112,19 +112,19 @@ function {$listenerFunction} () { {$attributeJavascript}; } var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); - - {$elementName}Array.forEach(function(element){ - if (element) { - element.{$eventName} = function (event) { - var targetElement = element; - if (event && event.target) { - targetElement = event.target; + if({$elementName}Array.lenght !== 'undefined'){ + {$elementName}Array.forEach(function(element){ + if (element) { + element.{$eventName} = function (event) { + var targetElement = element; + if (event && event.target) { + targetElement = event.target; + } + {$listenerFunction}.apply(targetElement); } - {$listenerFunction}.apply(targetElement); } - } - }); - + }); + } script; From 08ca835531a52d74649e1dd01bccd3b1c9f1cf8f Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Thu, 22 Oct 2020 02:07:59 +0530 Subject: [PATCH 021/346] Converted TEST into automic groups for reusable actions --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 ------------------- ...minCreateWidgetWthoutLayoutActionGroup.xml | 26 +++++++++++++ .../AdminWidgetAddLayoutUpdateActionGroup.xml | 18 +++++++++ ...minWidgetDeleteLayoutUpdateActionGroup.xml | 17 +++++++++ ...AddAndDeleteMultipleLayoutSectionsTest.xml | 11 +++++- .../View/Helper/SecureHtmlRenderer.php | 2 +- 6 files changed, 72 insertions(+), 40 deletions(-) delete mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml deleted file mode 100644 index b7ebd09c2fcc6..0000000000000 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<actionGroups - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup"> - <annotations> - <description>Goes to the Admin Widget creation page. Add and delete multiple layouts</description> - </annotations> - <arguments> - <argument name="widget"/> - </arguments> - <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> - <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> - <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> - <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> - <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> - <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> - <waitForAjaxLoad stepKey="waitForLoad"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate2"/> - <waitForAjaxLoad stepKey="waitForLoad2"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate3"/> - <waitForAjaxLoad stepKey="waitForLoad3"/> - <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionThird}}" stepKey="clickThirdDeleteButton"/> - <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionSecond}}" stepKey="clickSecondDeleteButton"/> - <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionFirst}}" stepKey="clickFirstDeleteButton"/> - <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml new file mode 100644 index 0000000000000..e9ee80c1a5f2a --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateWidgetWthoutLayoutActionGroup"> + <annotations> + <description>Goes to the Admin Widget creation page without saving it</description> + </annotations> + <arguments> + <argument name="widget"/> + </arguments> + <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> + <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> + <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> + <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> + <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> + <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml new file mode 100644 index 0000000000000..fa73fa4926e10 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminWidgetAddLayoutUpdateActionGroup"> + <annotations> + <description>Add layouts during widgets creation</description> + </annotations> + <waitForAjaxLoad stepKey="waitForLoad"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml new file mode 100644 index 0000000000000..e52fb1a7f6514 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminWidgetDeleteLayoutUpdateActionGroup"> + <annotations> + <description>Delete layouts during widgets creation</description> + </annotations> + <click selector="{{AdminNewWidgetSection.deleteWidgetLayoutAction}}" stepKey="clickFirstDeleteButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml index 5a5652e1e9049..eee6058836f2e 100644 --- a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml @@ -29,8 +29,17 @@ <argument name="title" value="{{AdminMenuContentElementsWidgets.pageTitle}}"/> </actionGroup> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> - <actionGroup ref="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup" stepKey="addWidgetForTest"> + <actionGroup ref="AdminCreateWidgetWthoutLayoutActionGroup" stepKey="addWidgetForTest"> <argument name="widget" value="ProductsListWidget"/> </actionGroup> + <actionGroup ref="AdminWidgetAddLayoutUpdateActionGroup" stepKey="AddSecondLayout"/> + <actionGroup ref="AdminWidgetAddLayoutUpdateActionGroup" stepKey="AddThirdLayout"/> + <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteFirstLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteSecondLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteThirdLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> </test> </tests> diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index ebc4b8870538f..87d4e88295356 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -112,7 +112,7 @@ function {$listenerFunction} () { {$attributeJavascript}; } var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); - if({$elementName}Array.lenght !== 'undefined'){ + if({$elementName}Array.length !== 'undefined'){ {$elementName}Array.forEach(function(element){ if (element) { element.{$eventName} = function (event) { From 788c26c8ed32630e8ab352c3f48d0764708cc0c6 Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Mon, 26 Oct 2020 17:32:16 +0530 Subject: [PATCH 022/346] Added event prevent code --- .../Magento/Framework/View/Helper/SecureHtmlRenderer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index 87d4e88295356..d3d94dbb7f1eb 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -116,6 +116,7 @@ function {$listenerFunction} () { {$elementName}Array.forEach(function(element){ if (element) { element.{$eventName} = function (event) { + event.preventDefault(); var targetElement = element; if (event && event.target) { targetElement = event.target; From 6359ac54873ff9d106f830e5b27c251823617b71 Mon Sep 17 00:00:00 2001 From: govindasharma974 <govindpokhrelsharma@cedcommerce.com> Date: Wed, 28 Oct 2020 16:50:53 +0530 Subject: [PATCH 023/346] Fixed MFTF issue --- .../Magento/Sales/Test/Mftf/Page/AdminCreditMemoViewPage.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoViewPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoViewPage.xml index 2e61424b29a56..2a3bc814364ae 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoViewPage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminCreditMemoViewPage.xml @@ -8,7 +8,7 @@ <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> - <page name="AdminCreditMemoViewPage" url="sales/order_creditmemo/view/creditmemo_id/{{memoId}}/" parameterized="true" area="admin" module="Magento_Sales"> + <page name="AdminCreditMemoViewPage" url="sales/creditmemo/view/creditmemo_id/" area="admin" module="Magento_Sales"> <section name="AdminCreditMemoViewItemsSection"/> <section name="AdminCreditMemoViewTotalSection"/> </page> From 2716339b3c3c97e9af35ef6aecaf634b1fce8f8d Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Wed, 28 Oct 2020 17:25:55 -0500 Subject: [PATCH 024/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Model/Coupon/Quote/UpdateCouponUsages.php | 18 +-- .../SalesRule/Model/CouponUsageConsumer.php | 104 ++++++++++++++++++ .../Model/Service/CouponUsageScheduler.php | 99 +++++++++++++++++ .../Magento/SalesRule/etc/communication.xml | 3 + app/code/Magento/SalesRule/etc/queue.xml | 3 + .../Magento/SalesRule/etc/queue_consumer.xml | 1 + .../Magento/SalesRule/etc/queue_publisher.xml | 3 + .../Magento/SalesRule/etc/queue_topology.xml | 1 + 8 files changed, 223 insertions(+), 9 deletions(-) create mode 100644 app/code/Magento/SalesRule/Model/CouponUsageConsumer.php create mode 100644 app/code/Magento/SalesRule/Model/Service/CouponUsageScheduler.php diff --git a/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php b/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php index 0ee2ee09cad57..8f29dd8e0a63c 100644 --- a/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php +++ b/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php @@ -8,9 +8,9 @@ namespace Magento\SalesRule\Model\Coupon\Quote; use Magento\Quote\Api\Data\CartInterface; -use Magento\SalesRule\Model\Coupon\Usage\Processor as CouponUsageProcessor; use Magento\SalesRule\Model\Coupon\Usage\UpdateInfo; use Magento\SalesRule\Model\Coupon\Usage\UpdateInfoFactory; +use Magento\SalesRule\Model\Service\CouponUsageScheduler; /** * Updates the coupon usages from quote @@ -18,24 +18,24 @@ class UpdateCouponUsages { /** - * @var CouponUsageProcessor + * @var UpdateInfoFactory */ - private $couponUsageProcessor; + private $updateInfoFactory; /** - * @var UpdateInfoFactory + * @var CouponUsageScheduler */ - private $updateInfoFactory; + private $couponUsageScheduler; /** - * @param CouponUsageProcessor $couponUsageProcessor + * @param CouponUsageScheduler $couponUsageScheduler * @param UpdateInfoFactory $updateInfoFactory */ public function __construct( - CouponUsageProcessor $couponUsageProcessor, + CouponUsageScheduler $couponUsageScheduler, UpdateInfoFactory $updateInfoFactory ) { - $this->couponUsageProcessor = $couponUsageProcessor; + $this->couponUsageScheduler = $couponUsageScheduler; $this->updateInfoFactory = $updateInfoFactory; } @@ -59,6 +59,6 @@ public function execute(CartInterface $quote, bool $increment): void $updateInfo->setCustomerId((int)$quote->getCustomerId()); $updateInfo->setIsIncrement($increment); - $this->couponUsageProcessor->process($updateInfo); + $this->couponUsageScheduler->schedule($updateInfo); } } diff --git a/app/code/Magento/SalesRule/Model/CouponUsageConsumer.php b/app/code/Magento/SalesRule/Model/CouponUsageConsumer.php new file mode 100644 index 0000000000000..c84d5f90a1125 --- /dev/null +++ b/app/code/Magento/SalesRule/Model/CouponUsageConsumer.php @@ -0,0 +1,104 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\SalesRule\Model; + +use Magento\SalesRule\Model\Coupon\Usage\UpdateInfoFactory; +use Magento\SalesRule\Model\Coupon\Usage\Processor as CouponUsageProcessor; +use Magento\AsynchronousOperations\Api\Data\OperationInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\EntityManager\EntityManager; +use Magento\Framework\Exception\NotFoundException; +use Psr\Log\LoggerInterface; + +/** + * Consumer for coupon usage update + */ +class CouponUsageConsumer +{ + /** + * @var SerializerInterface + */ + private $serializer; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var CouponUsageProcessor + */ + private $processor; + + /** + * @var EntityManager + */ + private $entityManager; + + /** + * @var UpdateInfoFactory + */ + private $updateInfoFactory; + + /** + * @param UpdateInfoFactory $updateInfoFactory + * @param CouponUsageProcessor $processor + * @param LoggerInterface $logger + * @param SerializerInterface $serializer + * @param EntityManager $entityManager + */ + public function __construct( + UpdateInfoFactory $updateInfoFactory, + CouponUsageProcessor $processor, + LoggerInterface $logger, + SerializerInterface $serializer, + EntityManager $entityManager + ) { + $this->updateInfoFactory = $updateInfoFactory; + $this->processor = $processor; + $this->logger = $logger; + $this->serializer = $serializer; + $this->entityManager = $entityManager; + } + + /** + * Process coupon usage update + * + * @param OperationInterface $operation + * @return void + * @throws \Exception + */ + public function process(OperationInterface $operation): void + { + $q = 2; + + try { + $serializedData = $operation->getSerializedData(); + $data = $this->serializer->unserialize($serializedData); + $updateInfo = $this->updateInfoFactory->create(); + $updateInfo->setData($data); + $this->processor->process($updateInfo); + } catch (NotFoundException $e) { + $this->logger->critical($e->getMessage()); + $status = OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED; + $errorCode = $e->getCode(); + $message = $e->getMessage(); + } catch (\Exception $e) { + $this->logger->critical($e->getMessage()); + $status = OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED; + $errorCode = $e->getCode(); + $message = __('Sorry, something went wrong during rule usage update. Please see log for details.'); + } + + $operation->setStatus($status ?? OperationInterface::STATUS_TYPE_COMPLETE) + ->setErrorCode($errorCode ?? null) + ->setResultMessage($message ?? null); + + $this->entityManager->save($operation); + } +} diff --git a/app/code/Magento/SalesRule/Model/Service/CouponUsageScheduler.php b/app/code/Magento/SalesRule/Model/Service/CouponUsageScheduler.php new file mode 100644 index 0000000000000..79ecfb61290df --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Service/CouponUsageScheduler.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\SalesRule\Model\Service; + +use Magento\Framework\Bulk\BulkManagementInterface; +use Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory; +use Magento\Framework\DataObject\IdentityGeneratorInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\Bulk\OperationInterface; +use Magento\Authorization\Model\UserContextInterface; +use Magento\SalesRule\Model\Coupon\Usage\UpdateInfo; + +/** + * Scheduler for coupon usage queue + */ +class CouponUsageScheduler +{ + private const TOPIC_NAME = 'sales.rule.update.coupon.usage'; + + /** + * @var BulkManagementInterface + */ + private $bulkManagement; + + /** + * @var OperationInterfaceFactory + */ + private $operationFactory; + + /** + * @var IdentityGeneratorInterface + */ + private $identityService; + + /** + * @var SerializerInterface + */ + private $serializer; + + /** + * @var UserContextInterface + */ + private $userContext; + + /** + * @param BulkManagementInterface $bulkManagement + * @param OperationInterfaceFactory $operartionFactory + * @param IdentityGeneratorInterface $identityService + * @param SerializerInterface $serializer + * @param UserContextInterface $userContext + */ + public function __construct( + BulkManagementInterface $bulkManagement, + OperationInterfaceFactory $operartionFactory, + IdentityGeneratorInterface $identityService, + SerializerInterface $serializer, + UserContextInterface $userContext + ) { + $this->bulkManagement = $bulkManagement; + $this->operationFactory = $operartionFactory; + $this->identityService = $identityService; + $this->serializer = $serializer; + $this->userContext = $userContext; + } + + /** + * Schedule sales rule usage info + * + * @param string $updateInfo + * @return boolean + */ + public function schedule(UpdateInfo $updateInfo): bool + { + $bulkUuid = $this->identityService->generateId(); + $bulkDescription = __('Rule processing: %1', implode(',', $updateInfo->getAppliedRuleIds())); + + $data = [ + 'data' => [ + 'bulk_uuid' => $bulkUuid, + 'topic_name' => self::TOPIC_NAME, + 'serialized_data' => $this->serializer->serialize($updateInfo->getData()), + 'status' => OperationInterface::STATUS_TYPE_OPEN, + ] + ]; + $operation = $this->operationFactory->create($data); + + return $this->bulkManagement->scheduleBulk( + $bulkUuid, + [$operation], + $bulkDescription, + $this->userContext->getUserId() + ); + } +} diff --git a/app/code/Magento/SalesRule/etc/communication.xml b/app/code/Magento/SalesRule/etc/communication.xml index 4c905fa83e2fd..786e866f0e3c5 100644 --- a/app/code/Magento/SalesRule/etc/communication.xml +++ b/app/code/Magento/SalesRule/etc/communication.xml @@ -9,4 +9,7 @@ <topic name="sales_rule.codegenerator" request="Magento\SalesRule\Api\Data\CouponGenerationSpecInterface"> <handler name="codegeneratorProcessor" type="Magento\SalesRule\Model\Coupon\Consumer" method="process" /> </topic> + <topic name="sales.rule.update.coupon.usage" request="Magento\AsynchronousOperations\Api\Data\OperationInterface"> + <handler name="sales.rule.update.coupon.usage" type="Magento\SalesRule\Model\CouponUsageConsumer" method="process" /> + </topic> </config> diff --git a/app/code/Magento/SalesRule/etc/queue.xml b/app/code/Magento/SalesRule/etc/queue.xml index 8217a0b9f6c1a..87dce71b53054 100644 --- a/app/code/Magento/SalesRule/etc/queue.xml +++ b/app/code/Magento/SalesRule/etc/queue.xml @@ -9,4 +9,7 @@ <broker topic="sales_rule.codegenerator" exchange="magento-db" type="db"> <queue name="codegenerator" consumer="codegeneratorProcessor" consumerInstance="Magento\Framework\MessageQueue\Consumer" handler="Magento\SalesRule\Model\Coupon\Consumer::process"/> </broker> + <broker topic="sales.rule.update.coupon.usage" exchange="magento-db" type="db"> + <queue name="sales.rule.update.coupon.usage" consumer="sales.rule.update.coupon.usage" consumerInstance="Magento\Framework\MessageQueue\Consumer" handler="Magento\SalesRule\Model\CouponUsageConsumer::process"/> + </broker> </config> diff --git a/app/code/Magento/SalesRule/etc/queue_consumer.xml b/app/code/Magento/SalesRule/etc/queue_consumer.xml index 9eb585f48e8e3..bcebaf6a543b9 100644 --- a/app/code/Magento/SalesRule/etc/queue_consumer.xml +++ b/app/code/Magento/SalesRule/etc/queue_consumer.xml @@ -7,4 +7,5 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> <consumer name="codegeneratorProcessor" queue="codegenerator" connection="db" maxMessages="5000" consumerInstance="Magento\Framework\MessageQueue\Consumer" handler="Magento\SalesRule\Model\Coupon\Consumer::process" /> + <consumer name="sales.rule.update.coupon.usage" queue="sales.rule.update.coupon.usage" connection="db" maxMessages="5000" consumerInstance="Magento\Framework\MessageQueue\Consumer" handler="Magento\SalesRule\Model\CouponUsageConsumer::process" /> </config> diff --git a/app/code/Magento/SalesRule/etc/queue_publisher.xml b/app/code/Magento/SalesRule/etc/queue_publisher.xml index 0863fba2307c5..f1b8bddf2c090 100644 --- a/app/code/Magento/SalesRule/etc/queue_publisher.xml +++ b/app/code/Magento/SalesRule/etc/queue_publisher.xml @@ -9,4 +9,7 @@ <publisher topic="sales_rule.codegenerator"> <connection name="db" exchange="magento-db" /> </publisher> + <publisher topic="sales.rule.update.coupon.usage"> + <connection name="db" exchange="magento-db" /> + </publisher> </config> diff --git a/app/code/Magento/SalesRule/etc/queue_topology.xml b/app/code/Magento/SalesRule/etc/queue_topology.xml index fd6a9bf36721c..3902c8a3ab36f 100644 --- a/app/code/Magento/SalesRule/etc/queue_topology.xml +++ b/app/code/Magento/SalesRule/etc/queue_topology.xml @@ -8,5 +8,6 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> <exchange name="magento-db" type="topic" connection="db"> <binding id="codegeneratorBinding" topic="sales_rule.codegenerator" destinationType="queue" destination="codegenerator"/> + <binding id="couponUsageBinding" topic="sales.rule.update.coupon.usage" destinationType="queue" destination="sales.rule.update.coupon.usage"/> </exchange> </config> From ade5168bb1a2228e5b18b65d4e295be4be74af4c Mon Sep 17 00:00:00 2001 From: govindasharma974 <govindpokhrelsharma@cedcommerce.com> Date: Thu, 29 Oct 2020 17:29:42 +0530 Subject: [PATCH 025/346] updated test files --- .../Adminhtml/Order/Creditmemo/ViewTest.php | 2 +- .../Adminhtml/Order/Invoice/ViewTest.php | 55 ++++++++++++++++--- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php index b6935269e3da7..6e04f4caadc8f 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php @@ -108,7 +108,7 @@ class ViewTest extends TestCase protected $pageTitleMock; /** - * @var \Magento\Shipping\Controller\Adminhtml\Order\Creditmemo\View + * @var \Magento\Sales\Controller\Adminhtml\Order\Creditmemo\View * @var RedirectFactory|MockObject */ protected $resultRedirectFactoryMock; diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php index c8376ab379b6f..a29ab201e0bd9 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php @@ -13,6 +13,8 @@ use Magento\Backend\Model\View\Result\Forward; use Magento\Backend\Model\View\Result\ForwardFactory; use Magento\Backend\Model\View\Result\Page; +use Magento\Backend\Model\View\Result\Redirect; +use Magento\Backend\Model\View\Result\RedirectFactory; use Magento\Framework\App\ActionFlag; use Magento\Framework\App\Request\Http; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -82,6 +84,17 @@ class ViewTest extends TestCase */ protected $pageTitleMock; + /** + * @var \Magento\Sales\Controller\Adminhtml\Order\Invoice\View + * @var RedirectFactory|MockObject + */ + protected $resultRedirectFactoryMock; + + /** + * @var Redirect|MockObject + */ + protected $resultRedirectMock; + /** * @var View */ @@ -194,6 +207,13 @@ protected function setUp(): void )->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); + $this->resultRedirectFactoryMock = $this->getMockBuilder(RedirectFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->resultRedirectMock = $this->getMockBuilder(Redirect::class) + ->disableOriginalConstructor() + ->getMock(); $this->invoiceRepository = $this->getMockBuilder(InvoiceRepositoryInterface::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); @@ -203,7 +223,8 @@ protected function setUp(): void [ 'context' => $contextMock, 'resultPageFactory' => $this->resultPageFactoryMock, - 'resultForwardFactory' => $this->resultForwardFactoryMock + 'resultForwardFactory' => $this->resultForwardFactoryMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock ] ); @@ -287,16 +308,32 @@ public function testExecuteNoInvoice() ->method('get') ->willReturn(null); - $resultForward = $this->getMockBuilder(Forward::class) - ->disableOriginalConstructor() - ->setMethods([]) - ->getMock(); - $resultForward->expects($this->once())->method('forward')->with(('noroute'))->willReturnSelf(); + $this->prepareRedirect(); + $this->setPath('sales/invoice'); + $this->assertInstanceOf( + Redirect::class, + $this->controller->execute() + ); + } - $this->resultForwardFactoryMock->expects($this->once()) + /** + * prepareRedirect + */ + protected function prepareRedirect() + { + $this->resultRedirectFactoryMock->expects($this->once()) ->method('create') - ->willReturn($resultForward); + ->willReturn($this->resultRedirectMock); + } - $this->assertSame($resultForward, $this->controller->execute()); + /** + * @param string $path + * @param array $params + */ + protected function setPath($path, $params = []) + { + $this->resultRedirectMock->expects($this->once()) + ->method('setPath') + ->with($path, $params); } } From 47d016b09da639508939187506300bf47f3e1e10 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Thu, 29 Oct 2020 10:45:55 -0500 Subject: [PATCH 026/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- app/code/Magento/SalesRule/Model/CouponUsageConsumer.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/CouponUsageConsumer.php b/app/code/Magento/SalesRule/Model/CouponUsageConsumer.php index c84d5f90a1125..0520cb658e408 100644 --- a/app/code/Magento/SalesRule/Model/CouponUsageConsumer.php +++ b/app/code/Magento/SalesRule/Model/CouponUsageConsumer.php @@ -75,8 +75,6 @@ public function __construct( */ public function process(OperationInterface $operation): void { - $q = 2; - try { $serializedData = $operation->getSerializedData(); $data = $this->serializer->unserialize($serializedData); From 585a937b065bc798e491aec9bee73eb3280d7158 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Thu, 29 Oct 2020 10:48:16 -0500 Subject: [PATCH 027/346] MDVA-31238: Problems with indexer --- app/code/Magento/SalesRule/composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json index 572e191093275..580455b693153 100644 --- a/app/code/Magento/SalesRule/composer.json +++ b/app/code/Magento/SalesRule/composer.json @@ -25,7 +25,8 @@ "magento/module-widget": "*", "magento/module-captcha": "*", "magento/module-checkout": "*", - "magento/module-authorization": "*" + "magento/module-authorization": "*", + "magento/module-asynchronous-operations": "*" }, "suggest": { "magento/module-sales-rule-sample-data": "*" From 91f35a10457494a9a848775b58ad1797870bff12 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Thu, 29 Oct 2020 10:49:56 -0500 Subject: [PATCH 028/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- app/code/Magento/SalesRule/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json index 580455b693153..20246f67e337e 100644 --- a/app/code/Magento/SalesRule/composer.json +++ b/app/code/Magento/SalesRule/composer.json @@ -7,6 +7,7 @@ "require": { "php": "~7.3.0||~7.4.0", "magento/framework": "*", + "magento/framework-bulk": "*", "magento/module-backend": "*", "magento/module-catalog": "*", "magento/module-catalog-rule": "*", From b6cb6972a4da820a87188a7778214479f8cff6a4 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Thu, 29 Oct 2020 17:16:29 -0500 Subject: [PATCH 029/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- app/code/Magento/Catalog/etc/di.xml | 5 ++ .../Model/Coupon/Quote/UpdateCouponUsages.php | 14 +++--- ...Scheduler.php => CouponUsagePublisher.php} | 6 +-- .../SalesRule/Plugin/CouponUsagesTest.php | 50 +++++++++++++++++++ 4 files changed, 65 insertions(+), 10 deletions(-) rename app/code/Magento/SalesRule/Model/Service/{CouponUsageScheduler.php => CouponUsagePublisher.php} (95%) diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 8a116282e2578..149003104a9fd 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -1319,4 +1319,9 @@ </argument> </arguments> </type> + <type name="Magento\Catalog\Model\Category\Attribute\Backend\Image"> + <arguments> + <argument name="imageUploader" xsi:type="object">Magento\Catalog\CategoryImageUpload</argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php b/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php index 8f29dd8e0a63c..02da921e032e0 100644 --- a/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php +++ b/app/code/Magento/SalesRule/Model/Coupon/Quote/UpdateCouponUsages.php @@ -10,7 +10,7 @@ use Magento\Quote\Api\Data\CartInterface; use Magento\SalesRule\Model\Coupon\Usage\UpdateInfo; use Magento\SalesRule\Model\Coupon\Usage\UpdateInfoFactory; -use Magento\SalesRule\Model\Service\CouponUsageScheduler; +use Magento\SalesRule\Model\Service\CouponUsagePublisher; /** * Updates the coupon usages from quote @@ -23,19 +23,19 @@ class UpdateCouponUsages private $updateInfoFactory; /** - * @var CouponUsageScheduler + * @var CouponUsagePublisher */ - private $couponUsageScheduler; + private $couponUsagePublisher; /** - * @param CouponUsageScheduler $couponUsageScheduler + * @param CouponUsagePublisher $couponUsagePublisher * @param UpdateInfoFactory $updateInfoFactory */ public function __construct( - CouponUsageScheduler $couponUsageScheduler, + CouponUsagePublisher $couponUsagePublisher, UpdateInfoFactory $updateInfoFactory ) { - $this->couponUsageScheduler = $couponUsageScheduler; + $this->couponUsagePublisher = $couponUsagePublisher; $this->updateInfoFactory = $updateInfoFactory; } @@ -59,6 +59,6 @@ public function execute(CartInterface $quote, bool $increment): void $updateInfo->setCustomerId((int)$quote->getCustomerId()); $updateInfo->setIsIncrement($increment); - $this->couponUsageScheduler->schedule($updateInfo); + $this->couponUsagePublisher->publish($updateInfo); } } diff --git a/app/code/Magento/SalesRule/Model/Service/CouponUsageScheduler.php b/app/code/Magento/SalesRule/Model/Service/CouponUsagePublisher.php similarity index 95% rename from app/code/Magento/SalesRule/Model/Service/CouponUsageScheduler.php rename to app/code/Magento/SalesRule/Model/Service/CouponUsagePublisher.php index 79ecfb61290df..1d1bbb1f63ed3 100644 --- a/app/code/Magento/SalesRule/Model/Service/CouponUsageScheduler.php +++ b/app/code/Magento/SalesRule/Model/Service/CouponUsagePublisher.php @@ -18,7 +18,7 @@ /** * Scheduler for coupon usage queue */ -class CouponUsageScheduler +class CouponUsagePublisher { private const TOPIC_NAME = 'sales.rule.update.coupon.usage'; @@ -69,12 +69,12 @@ public function __construct( } /** - * Schedule sales rule usage info + * Publish sales rule usage info into the queue * * @param string $updateInfo * @return boolean */ - public function schedule(UpdateInfo $updateInfo): bool + public function publish(UpdateInfo $updateInfo): bool { $bulkUuid = $this->identityService->generateId(); $bulkDescription = __('Rule processing: %1', implode(',', $updateInfo->getAppliedRuleIds())); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php index 4ed096fa4418a..bf8e9174a8216 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php @@ -14,6 +14,9 @@ use Magento\SalesRule\Model\Coupon; use Magento\SalesRule\Model\ResourceModel\Coupon\Usage; use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\MessageQueue\EnvironmentPreconditionException; +use Magento\TestFramework\MessageQueue\PreconditionFailedException; +use Magento\TestFramework\MessageQueue\PublisherConsumerController; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -26,6 +29,16 @@ */ class CouponUsagesTest extends TestCase { + /** + * @var PublisherConsumerController + */ + private $publisherConsumerController; + + /** + * @var array + */ + private $consumers = ['sales.rule.update.coupon.usage']; + /** * @var ObjectManagerInterface */ @@ -61,6 +74,35 @@ protected function setUp(): void $this->couponUsage = $this->objectManager->get(DataObject::class); $this->quoteManagement = $this->objectManager->get(QuoteManagement::class); $this->orderService = $this->objectManager->get(OrderService::class); + + $this->publisherConsumerController = Bootstrap::getObjectManager()->create( + PublisherConsumerController::class, + [ + 'consumers' => $this->consumers, + 'logFilePath' => TESTS_TEMP_DIR . "/MessageQueueTestLog.txt", + 'maxMessages' => null, + 'appInitParams' => Bootstrap::getInstance()->getAppInitParams() + ] + ); + try { + $this->publisherConsumerController->startConsumers(); + } catch (EnvironmentPreconditionException $e) { + $this->markTestSkipped($e->getMessage()); + } catch (PreconditionFailedException $e) { + $this->fail( + $e->getMessage() + ); + } + parent::setUp(); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + $this->publisherConsumerController->stopConsumers(); + parent::tearDown(); } /** @@ -74,6 +116,11 @@ public function testSubmitQuoteAndCancelOrder() $couponCode = 'one_usage'; $reservedOrderId = 'test01'; + $binDirectory = realpath(INTEGRATION_TESTS_DIR . '/bin/'); + $magentoCli = $binDirectory . '/magento'; + $consumerStartCommand = "php {$magentoCli} queue:consumers:start sales.rule.update.coupon.usage &"; + exec($consumerStartCommand); + /** @var Coupon $coupon */ $coupon = $this->objectManager->get(Coupon::class); $coupon->loadByCode($couponCode); @@ -83,6 +130,9 @@ public function testSubmitQuoteAndCancelOrder() // Make sure coupon usages value is incremented then order is placed. $order = $this->quoteManagement->submit($quote); + + + sleep(15); // timeout to processing Magento queue $this->usage->loadByCustomerCoupon($this->couponUsage, $customerId, $coupon->getId()); $coupon->loadByCode($couponCode); From a72c0431710c8136b185b17dea059217dee49b53 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Mon, 2 Nov 2020 14:54:37 -0600 Subject: [PATCH 030/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php index bf8e9174a8216..cc23259dba58c 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php @@ -109,6 +109,7 @@ protected function tearDown(): void * Test increasing coupon usages after after order placing and decreasing after order cancellation. * * @magentoDataFixture Magento/SalesRule/_files/coupons_limited_order.php + * @magentoDbIsolation disabled */ public function testSubmitQuoteAndCancelOrder() { @@ -130,9 +131,7 @@ public function testSubmitQuoteAndCancelOrder() // Make sure coupon usages value is incremented then order is placed. $order = $this->quoteManagement->submit($quote); - - - sleep(15); // timeout to processing Magento queue + sleep(10); // timeout to processing Magento queue $this->usage->loadByCustomerCoupon($this->couponUsage, $customerId, $coupon->getId()); $coupon->loadByCode($couponCode); From 986ac9904fd303ddc6025caed33863a32e6e2242 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Mon, 2 Nov 2020 15:48:07 -0600 Subject: [PATCH 031/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Magento/SalesRule/Plugin/CouponUsagesTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php index cc23259dba58c..e7732f742b591 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php @@ -80,7 +80,7 @@ protected function setUp(): void [ 'consumers' => $this->consumers, 'logFilePath' => TESTS_TEMP_DIR . "/MessageQueueTestLog.txt", - 'maxMessages' => null, + 'maxMessages' => 100, 'appInitParams' => Bootstrap::getInstance()->getAppInitParams() ] ); @@ -117,10 +117,7 @@ public function testSubmitQuoteAndCancelOrder() $couponCode = 'one_usage'; $reservedOrderId = 'test01'; - $binDirectory = realpath(INTEGRATION_TESTS_DIR . '/bin/'); - $magentoCli = $binDirectory . '/magento'; - $consumerStartCommand = "php {$magentoCli} queue:consumers:start sales.rule.update.coupon.usage &"; - exec($consumerStartCommand); + $this->publisherConsumerController->startConsumers(); /** @var Coupon $coupon */ $coupon = $this->objectManager->get(Coupon::class); From e5918517b1e65e6036f108961986f2e38ff90efa Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Tue, 3 Nov 2020 06:35:29 -0600 Subject: [PATCH 032/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- app/code/Magento/Catalog/etc/di.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 149003104a9fd..8a116282e2578 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -1319,9 +1319,4 @@ </argument> </arguments> </type> - <type name="Magento\Catalog\Model\Category\Attribute\Backend\Image"> - <arguments> - <argument name="imageUploader" xsi:type="object">Magento\Catalog\CategoryImageUpload</argument> - </arguments> - </type> </config> From 09655eb97e40757b46d6efa596294143bd0a4eea Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Tue, 3 Nov 2020 06:45:48 -0600 Subject: [PATCH 033/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php index e7732f742b591..eebf5ea638d05 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Plugin/CouponUsagesTest.php @@ -26,6 +26,7 @@ * @magentoAppArea frontend * @magentoDbIsolation enabled * @magentoAppIsolation enabled + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CouponUsagesTest extends TestCase { From 248fc8dcf1ee672141c31c1e2268abcf6d8727f5 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Tue, 3 Nov 2020 07:07:17 -0600 Subject: [PATCH 034/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- ...minCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 6 ++++++ .../SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index 6ce9909d06be5..4c90e18b1195c 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -20,6 +20,12 @@ </annotations> <before> + <!-- Start Coupon Usage Consumer --> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue"> + <argument name="consumerName" value="{{SalesRuleCouponUsageConsumer.consumerName}}"/> + <argument name="maxMessages" value="{{SalesRuleCouponUsageConsumer.messageLimit}}"/> + </actionGroup> + <!-- Enable Zero Subtotal Checkout --> <magentoCLI command="config:set {{EnableZeroSubtotalCheckoutConfigData.path}} {{EnableZeroSubtotalCheckoutConfigData.value}}" stepKey="enableZeroSubtotalCheckout"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml index 3dd87d94d0148..d54b9fada0f4b 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml @@ -13,4 +13,8 @@ <data key="is_primary">1</data> <data key="times_used">0</data> </entity> + <entity name="SalesRuleCouponUsageConsumer"> + <data key="consumerName">sales.rule.update.coupon.usage</data> + <data key="messageLimit">100</data> + </entity> </entities> From fbad9a1e8d953f9424bea28492e77ebc663a7e8f Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Tue, 3 Nov 2020 10:26:59 -0600 Subject: [PATCH 035/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- ...AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index 4c90e18b1195c..8c64918696f1f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -22,8 +22,8 @@ <before> <!-- Start Coupon Usage Consumer --> <actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue"> - <argument name="consumerName" value="{{SalesRuleCouponUsageConsumer.consumerName}}"/> - <argument name="maxMessages" value="{{SalesRuleCouponUsageConsumer.messageLimit}}"/> + <argument name="consumerName" value="sales.rule.update.coupon.usage"/> + <argument name="maxMessages" value="1000"/> </actionGroup> <!-- Enable Zero Subtotal Checkout --> From 4fef4b43473d3ee4dc0fdb4a25cd29724b2bc801 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 3 Sep 2020 16:09:12 +0300 Subject: [PATCH 036/346] Mview patch update --- .../Framework/Mview/Config/Converter.php | 2 + lib/internal/Magento/Framework/Mview/View.php | 40 +++++++--- .../Mview/View/ChangeLogBatchIterator.php | 78 +++++++++++++++++++ .../View/ChangeLogBatchIteratorInterface.php | 30 +++++++ .../Framework/Mview/View/Changelog.php | 44 ++++++++++- .../Mview/View/ChangelogInterface.php | 5 ++ .../Framework/Mview/View/Subscription.php | 64 ++++++++++++--- .../Magento/Framework/Mview/etc/mview.xsd | 2 + 8 files changed, 239 insertions(+), 26 deletions(-) create mode 100644 lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php create mode 100644 lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php diff --git a/lib/internal/Magento/Framework/Mview/Config/Converter.php b/lib/internal/Magento/Framework/Mview/Config/Converter.php index 5c33ac150d00a..9cfa84483571c 100644 --- a/lib/internal/Magento/Framework/Mview/Config/Converter.php +++ b/lib/internal/Magento/Framework/Mview/Config/Converter.php @@ -28,6 +28,8 @@ public function convert($source) $data['view_id'] = $viewId; $data['action_class'] = $this->getAttributeValue($viewNode, 'class'); $data['group'] = $this->getAttributeValue($viewNode, 'group'); + $data['store_scope'] = $this->getAttributeValue($viewNode, 'store_scope'); + $data['attribute_scope'] = $this->getAttributeValue($viewNode, 'attribute_scope'); $data['subscriptions'] = []; /** @var $childNode \DOMNode */ diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index dade475a20482..98d54044c3b8f 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -10,6 +10,7 @@ use InvalidArgumentException; use Magento\Framework\DataObject; +use Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface; use Magento\Framework\Mview\View\ChangelogTableNotExistsException; use Magento\Framework\Mview\View\SubscriptionFactory; use Exception; @@ -67,6 +68,11 @@ class View extends DataObject implements ViewInterface */ private $changelogBatchSize; + /** + * @var ChangeLogBatchIteratorInterface[] + */ + private $strategies; + /** * @param ConfigInterface $config * @param ActionFactory $actionFactory @@ -75,6 +81,7 @@ class View extends DataObject implements ViewInterface * @param SubscriptionFactory $subscriptionFactory * @param array $data * @param array $changelogBatchSize + * @param array $strategies */ public function __construct( ConfigInterface $config, @@ -83,7 +90,8 @@ public function __construct( View\ChangelogInterface $changelog, SubscriptionFactory $subscriptionFactory, array $data = [], - array $changelogBatchSize = [] + array $changelogBatchSize = [], + array $strategies = [] ) { $this->config = $config; $this->actionFactory = $actionFactory; @@ -92,6 +100,7 @@ public function __construct( $this->subscriptionFactory = $subscriptionFactory; $this->changelogBatchSize = $changelogBatchSize; parent::__construct($data); + $this->strategies = $strategies; } /** @@ -196,7 +205,7 @@ public function load($viewId) */ public function subscribe() { - if ($this->getState()->getMode() !== View\StateInterface::MODE_ENABLED) { + //if ($this->getState()->getMode() !== View\StateInterface::MODE_ENABLED) { // Create changelog table $this->getChangelog()->create(); @@ -206,7 +215,7 @@ public function subscribe() // Update view state $this->getState()->setMode(View\StateInterface::MODE_ENABLED)->save(); - } + // } return $this; } @@ -240,7 +249,7 @@ public function unsubscribe() */ public function update() { - if (!$this->isIdle() || !$this->isEnabled()) { + if (!$this->isEnabled()) { return; } @@ -256,7 +265,7 @@ public function update() try { $this->getState()->setStatus(View\StateInterface::STATUS_WORKING)->save(); - $this->executeAction($action, $lastVersionId, $currentVersionId); + $this->executeAction($action, 0, 1); $this->getState()->loadByView($this->getId()); $statusToRestore = $this->getState()->getStatus() === View\StateInterface::STATUS_SUSPENDED @@ -297,13 +306,24 @@ private function executeAction(ActionInterface $action, int $lastVersionId, int $vsFrom = $lastVersionId; while ($vsFrom < $currentVersionId) { - $ids = $this->getBatchOfIds($vsFrom, $currentVersionId); - // We run the actual indexer in batches. - // Chunked AFTER loading to avoid duplicates in separate chunks. - $chunks = array_chunk($ids, $batchSize); - foreach ($chunks as $ids) { + if (isset($this->strategies[$this->changelog->getViewId()])) { + $changelogData = [ + 'name' => $this->changelog->getName(), + 'column_name' => $this->changelog->getColumnName(), + 'view_id' => $this->changelog->getViewId() + ]; + $ids = $this->strategies[$this->changelog->getViewId()]->walk($changelogData, $vsFrom, $batchSize); $action->execute($ids); + } else { + $ids = $this->getBatchOfIds($vsFrom, $currentVersionId); + // We run the actual indexer in batches. + // Chunked AFTER loading to avoid duplicates in separate chunks. + $chunks = array_chunk($ids, $batchSize); + foreach ($chunks as $ids) { + $action->execute($ids); + } } + } } diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php new file mode 100644 index 0000000000000..bc4aff56b941d --- /dev/null +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Mview\View; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Sql\Expression; +use Magento\Framework\Mview\Config; +use Magento\Framework\Phrase; + +/** + * Interface \Magento\Framework\Mview\View\ChangeLogBatchIterator + * + */ +class ChangeLogBatchIterator implements ChangeLogBatchIteratorInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var Config + */ + private $mviewConfig; + + /** + * ChangeLogBatchIterator constructor. + * @param ResourceConnection $resourceConnection + * @param Config $mviewConfig + */ + public function __construct( + ResourceConnection $resourceConnection, + Config $mviewConfig + ) { + $this->resourceConnection = $resourceConnection; + $this->mviewConfig = $mviewConfig; + } + + /** + * Walk through batches + * + * @param array $changeLogData + * @param $fromVersionId + * @param int $batchSize + * @return mixed + * @throws ChangelogTableNotExistsException + */ + public function walk(array $changeLogData, $fromVersionId, int $batchSize) + { + $configuration = $this->mviewConfig->getView($changeLogData['view_id']); + $connection = $this->resourceConnection->getConnection(); + $changelogTableName = $this->resourceConnection->getTableName($changeLogData['name']); + if (!$connection->isTableExists($changelogTableName)) { + throw new ChangelogTableNotExistsException(new Phrase("Table %1 does not exist", [$changelogTableName])); + } + $columns = [$changeLogData['column_name']]; + $select = $connection->select()->distinct(true) + ->where( + 'version_id > ?', + (int)$fromVersionId + ) + ->group([$changeLogData['column_name'], 'store_id']) + ->limit($batchSize); + + $columns = [ + $changeLogData['column_name'], + 'attribute_ids' => new Expression('GROUP_CONCAT(attribute_id)'), + 'store_id' + ]; + + $select->from($changelogTableName, $columns); + return $connection->fetchAll($select); + } +} diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php new file mode 100644 index 0000000000000..ec225a24c2963 --- /dev/null +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Mview\View; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Sql\Expression; +use Magento\Framework\Mview\Config; +use Magento\Framework\Phrase; + +/** + * Interface \Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface + * + */ +interface ChangeLogBatchIteratorInterface +{ + /** + * Walk through batches + * + * @param array $changeLogData + * @param $fromVersionId + * @param int $batchSize + * @return mixed + * @throws ChangelogTableNotExistsException + */ + public function walk(array $changeLogData, $fromVersionId, int $batchSize); +} diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index ce88a88556fe0..88ca9cd162c67 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -7,7 +7,9 @@ namespace Magento\Framework\Mview\View; use Magento\Framework\DB\Adapter\ConnectionException; +use Magento\Framework\DB\Sql\Expression; use Magento\Framework\Exception\RuntimeException; +use Magento\Framework\Mview\Config; use Magento\Framework\Phrase; /** @@ -25,6 +27,11 @@ class Changelog implements ChangelogInterface */ const COLUMN_NAME = 'entity_id'; + /** + * Version ID column name + */ + const VERSION_ID_COLUMN_NAME = 'version_id'; + /** * Database connection * @@ -44,15 +51,24 @@ class Changelog implements ChangelogInterface */ protected $resource; + /** + * @var Config + */ + private $mviewConfig; + /** * @param \Magento\Framework\App\ResourceConnection $resource + * @param Config $mviewConfig * @throws ConnectionException */ - public function __construct(\Magento\Framework\App\ResourceConnection $resource) - { + public function __construct( + \Magento\Framework\App\ResourceConnection $resource, + Config $mviewConfig + ) { $this->connection = $resource->getConnection(); $this->resource = $resource; $this->checkConnection(); + $this->mviewConfig = $mviewConfig; } /** @@ -78,12 +94,13 @@ protected function checkConnection() */ public function create() { + $config = $this->mviewConfig->getView($this->getViewId()); $changelogTableName = $this->resource->getTableName($this->getName()); if (!$this->connection->isTableExists($changelogTableName)) { $table = $this->connection->newTable( $changelogTableName )->addColumn( - 'version_id', + self::VERSION_ID_COLUMN_NAME, \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], @@ -95,6 +112,25 @@ public function create() ['unsigned' => true, 'nullable' => false, 'default' => '0'], 'Entity ID' ); + if ($config[self::ATTRIBUTE_SCOPE_SUPPORT]) { + $table->addColumn( + self::ATTRIBUTE_COLUMN, + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false, 'default' => '0'], + 'Attribute ID' + ); + } + if ($config[self::STORE_SCOPE_SUPPORT]) { + $table->addColumn( + self::STORE_COLUMN, + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false, 'default' => '0'], + 'Store ID' + ); + } + $this->connection->createTable($table); } } @@ -139,7 +175,7 @@ public function clear($versionId) * * @param int $fromVersionId * @param int $toVersionId - * @return int[] + * @return array * @throws ChangelogTableNotExistsException */ public function getList($fromVersionId, $toVersionId) diff --git a/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php b/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php index b00c1ca3a2e33..79f998cbe02b6 100644 --- a/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php +++ b/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php @@ -11,6 +11,11 @@ */ interface ChangelogInterface { + const ATTRIBUTE_SCOPE_SUPPORT = 'attribute_scope'; + const STORE_SCOPE_SUPPORT = 'store_scope'; + const ATTRIBUTE_COLUMN = 'attribute_id'; + const STORE_COLUMN = 'store_id'; + /** * Create changelog table * diff --git a/lib/internal/Magento/Framework/Mview/View/Subscription.php b/lib/internal/Magento/Framework/Mview/View/Subscription.php index ddfa39f0a089f..2b94b9c26a21d 100644 --- a/lib/internal/Magento/Framework/Mview/View/Subscription.php +++ b/lib/internal/Magento/Framework/Mview/View/Subscription.php @@ -6,8 +6,10 @@ namespace Magento\Framework\Mview\View; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Ddl\Trigger; +use Magento\Framework\Mview\Config; use Magento\Framework\Mview\View\StateInterface; /** @@ -68,12 +70,17 @@ class Subscription implements SubscriptionInterface * @var Resource */ protected $resource; + /** + * @var Config + */ + private $mviewConfig; /** * @param ResourceConnection $resource * @param \Magento\Framework\DB\Ddl\TriggerFactory $triggerFactory * @param \Magento\Framework\Mview\View\CollectionInterface $viewCollection * @param \Magento\Framework\Mview\ViewInterface $view + * @param Config $mviewConfig * @param string $tableName * @param string $columnName * @param array $ignoredUpdateColumns @@ -85,7 +92,8 @@ public function __construct( \Magento\Framework\Mview\ViewInterface $view, $tableName, $columnName, - $ignoredUpdateColumns = [] + $ignoredUpdateColumns = [], + Config $mviewConfig = null ) { $this->connection = $resource->getConnection(); $this->triggerFactory = $triggerFactory; @@ -95,6 +103,7 @@ public function __construct( $this->columnName = $columnName; $this->resource = $resource; $this->ignoredUpdateColumns = $ignoredUpdateColumns; + $this->mviewConfig = $mviewConfig ?? ObjectManager::getInstance()->get(Config::class); } /** @@ -198,13 +207,10 @@ protected function getLinkedViews() */ protected function buildStatement($event, $changelog) { + $trigger = "INSERT IGNORE INTO %s (%s) VALUES (%s);"; switch ($event) { - case Trigger::EVENT_INSERT: - $trigger = "INSERT IGNORE INTO %s (%s) VALUES (NEW.%s);"; - break; case Trigger::EVENT_UPDATE: $tableName = $this->resource->getTableName($this->getTableName()); - $trigger = "INSERT IGNORE INTO %s (%s) VALUES (NEW.%s);"; if ($this->connection->isTableExists($tableName) && $describe = $this->connection->describeTable($tableName) ) { @@ -226,20 +232,54 @@ protected function buildStatement($event, $changelog) } } break; - case Trigger::EVENT_DELETE: - $trigger = "INSERT IGNORE INTO %s (%s) VALUES (OLD.%s);"; - break; - default: - return ''; } + list($columnNames, $columnValues) = $this->prepareTriggerBody($changelog, $event); return sprintf( $trigger, $this->connection->quoteIdentifier($this->resource->getTableName($changelog->getName())), - $this->connection->quoteIdentifier($changelog->getColumnName()), - $this->connection->quoteIdentifier($this->getColumnName()) + $columnNames, + $columnValues ); } + /** + * Prepare column names and column values for trigger body + * + * @param ChangelogInterface $changelog + * @param string $eventType + * @return array + */ + public function prepareTriggerBody(ChangelogInterface $changelog, string $eventType) + { + $prefix = $eventType === Trigger::EVENT_DELETE ? 'OLD.' : 'NEW.'; + $describedSubscribedColumns = array_column( + $this->connection->describeTable($this->getTableName()), + 'COLUMN_NAME' + ); + $viewConfig = $this->mviewConfig->getView($this->getView()->getId()); + $columnNames = [$this->connection->quoteIdentifier($changelog->getColumnName())]; + $columnValues = [$this->connection->quoteIdentifier($this->getColumnName())]; + //If we need to add attributes + if ($viewConfig[ChangelogInterface::ATTRIBUTE_SCOPE_SUPPORT] && + array_search(Changelog::ATTRIBUTE_COLUMN, $describedSubscribedColumns) + ) { + $columnValues[] = $prefix . $this->connection->quoteIdentifier(Changelog::ATTRIBUTE_COLUMN); + $columnNames[] = $this->connection->quoteIdentifier(Changelog::ATTRIBUTE_COLUMN); + } + //If we need to add stores + if ($viewConfig[ChangelogInterface::STORE_SCOPE_SUPPORT] && + array_search(Changelog::STORE_COLUMN, $describedSubscribedColumns) + ) { + $columnValues[] = $prefix . $this->connection->quoteIdentifier(Changelog::STORE_COLUMN); + $columnNames[] = $this->connection->quoteIdentifier(Changelog::STORE_COLUMN); + } + + return [ + implode(",", $columnNames), + implode(",", $columnValues) + ]; + } + /** * Build an "after" event for the given table and event * diff --git a/lib/internal/Magento/Framework/Mview/etc/mview.xsd b/lib/internal/Magento/Framework/Mview/etc/mview.xsd index dfff4964f6587..5b264efdf5445 100644 --- a/lib/internal/Magento/Framework/Mview/etc/mview.xsd +++ b/lib/internal/Magento/Framework/Mview/etc/mview.xsd @@ -46,6 +46,8 @@ <xs:attribute name="id" type="xs:string" use="required" /> <xs:attribute name="class" type="classType" use="required" /> <xs:attribute name="group" type="xs:string" use="required" /> + <xs:attribute name="store_scope" type="xs:boolean" use="optional" /> + <xs:attribute name="attribute_scope" type="xs:boolean" use="optional" /> </xs:complexType> <xs:simpleType name="classType"> From 0d18cce39964a8c4bda4a8cd71ddcee44d8fdcba Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 3 Sep 2020 16:16:11 +0300 Subject: [PATCH 037/346] Mview patch update --- lib/internal/Magento/Framework/Mview/View.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index 98d54044c3b8f..bc795915e6f7d 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -205,7 +205,7 @@ public function load($viewId) */ public function subscribe() { - //if ($this->getState()->getMode() !== View\StateInterface::MODE_ENABLED) { + if ($this->getState()->getMode() !== View\StateInterface::MODE_ENABLED) { // Create changelog table $this->getChangelog()->create(); @@ -215,7 +215,7 @@ public function subscribe() // Update view state $this->getState()->setMode(View\StateInterface::MODE_ENABLED)->save(); - // } + } return $this; } From dcc2ca25d847ae84af46a362cadfe3c4ae62eccc Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 3 Sep 2020 16:18:34 +0300 Subject: [PATCH 038/346] Mview patch update --- lib/internal/Magento/Framework/Mview/View.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index bc795915e6f7d..999c8c187735b 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -249,7 +249,7 @@ public function unsubscribe() */ public function update() { - if (!$this->isEnabled()) { + if (!$this->isIdle() || !$this->isEnabled()) { return; } From a77c41ced019ec483b21faa3267186ce2cecd5de Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 3 Sep 2020 16:20:17 +0300 Subject: [PATCH 039/346] Mview patch update --- lib/internal/Magento/Framework/Mview/View.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index 999c8c187735b..3cd5f9b28bcaf 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -265,7 +265,7 @@ public function update() try { $this->getState()->setStatus(View\StateInterface::STATUS_WORKING)->save(); - $this->executeAction($action, 0, 1); + $this->executeAction($action, $lastVersionId, $currentVersionId); $this->getState()->loadByView($this->getId()); $statusToRestore = $this->getState()->getStatus() === View\StateInterface::STATUS_SUSPENDED From 6071c5a5caadf2f146395dde679f4a51cd0d5174 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Tue, 8 Sep 2020 17:24:07 +0300 Subject: [PATCH 040/346] Mview patch update --- lib/internal/Magento/Framework/Mview/View.php | 1 + .../Framework/Mview/View/Changelog.php | 4 ++-- .../Framework/Mview/View/Subscription.php | 22 ++++++++++++++++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index 3cd5f9b28bcaf..1ad70aa2c33d3 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -313,6 +313,7 @@ private function executeAction(ActionInterface $action, int $lastVersionId, int 'view_id' => $this->changelog->getViewId() ]; $ids = $this->strategies[$this->changelog->getViewId()]->walk($changelogData, $vsFrom, $batchSize); + $vsFrom += $batchSize; $action->execute($ids); } else { $ids = $this->getBatchOfIds($vsFrom, $currentVersionId); diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index 88ca9cd162c67..2ade739d3197c 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -117,7 +117,7 @@ public function create() self::ATTRIBUTE_COLUMN, \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], + ['unsigned' => true, 'nullable' => true], 'Attribute ID' ); } @@ -126,7 +126,7 @@ public function create() self::STORE_COLUMN, \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], + ['unsigned' => true, 'nullable' => true], 'Store ID' ); } diff --git a/lib/internal/Magento/Framework/Mview/View/Subscription.php b/lib/internal/Magento/Framework/Mview/View/Subscription.php index 2b94b9c26a21d..460db5260f008 100644 --- a/lib/internal/Magento/Framework/Mview/View/Subscription.php +++ b/lib/internal/Magento/Framework/Mview/View/Subscription.php @@ -242,6 +242,15 @@ protected function buildStatement($event, $changelog) ); } + /** + * @param string $prefix + * @return string + */ + public function getEntityColumn(string $prefix): string + { + return $prefix . $this->connection->quoteIdentifier($this->getColumnName()); + } + /** * Prepare column names and column values for trigger body * @@ -256,19 +265,26 @@ public function prepareTriggerBody(ChangelogInterface $changelog, string $eventT $this->connection->describeTable($this->getTableName()), 'COLUMN_NAME' ); + $describedClColumns = array_column( + $this->connection->describeTable($changelog->getName()), + 'COLUMN_NAME' + ); $viewConfig = $this->mviewConfig->getView($this->getView()->getId()); $columnNames = [$this->connection->quoteIdentifier($changelog->getColumnName())]; - $columnValues = [$this->connection->quoteIdentifier($this->getColumnName())]; + $columnValues = [$this->getEntityColumn($prefix)]; //If we need to add attributes if ($viewConfig[ChangelogInterface::ATTRIBUTE_SCOPE_SUPPORT] && - array_search(Changelog::ATTRIBUTE_COLUMN, $describedSubscribedColumns) + array_search(Changelog::ATTRIBUTE_COLUMN, $describedSubscribedColumns) && + array_search(Changelog::ATTRIBUTE_COLUMN, $describedClColumns) + ) { $columnValues[] = $prefix . $this->connection->quoteIdentifier(Changelog::ATTRIBUTE_COLUMN); $columnNames[] = $this->connection->quoteIdentifier(Changelog::ATTRIBUTE_COLUMN); } //If we need to add stores if ($viewConfig[ChangelogInterface::STORE_SCOPE_SUPPORT] && - array_search(Changelog::STORE_COLUMN, $describedSubscribedColumns) + array_search(Changelog::STORE_COLUMN, $describedSubscribedColumns) && + array_search(Changelog::STORE_COLUMN, $describedClColumns) ) { $columnValues[] = $prefix . $this->connection->quoteIdentifier(Changelog::STORE_COLUMN); $columnNames[] = $this->connection->quoteIdentifier(Changelog::STORE_COLUMN); From 0e66e6cb6c58882704d39643b230966d8c0e7407 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Fri, 11 Sep 2020 18:00:05 +0300 Subject: [PATCH 041/346] Mview patch update -- move framework logic to saas-export --- lib/internal/Magento/Framework/Mview/View/Changelog.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index 2ade739d3197c..bbfb47807d4d6 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -112,7 +112,8 @@ public function create() ['unsigned' => true, 'nullable' => false, 'default' => '0'], 'Entity ID' ); - if ($config[self::ATTRIBUTE_SCOPE_SUPPORT]) { + + if ($config && $config[self::ATTRIBUTE_SCOPE_SUPPORT]) { $table->addColumn( self::ATTRIBUTE_COLUMN, \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, @@ -121,7 +122,7 @@ public function create() 'Attribute ID' ); } - if ($config[self::STORE_SCOPE_SUPPORT]) { + if ($config && $config[self::STORE_SCOPE_SUPPORT]) { $table->addColumn( self::STORE_COLUMN, \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, From c5d8fc649a007ba2aeb359c70ceabf3947f4124b Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Wed, 16 Sep 2020 15:31:14 +0300 Subject: [PATCH 042/346] Mview patch update -- move framework logic to saas-export --- .../Magento/Eav/Model/Mview/BatchIterator.php | 67 +++++++++++++ .../Framework/Mview/Config/Converter.php | 30 +++++- .../Mview/Test/Unit/View/ChangelogTest.php | 22 ++++- .../Mview/Test/Unit/View/SubscriptionTest.php | 37 +++++--- lib/internal/Magento/Framework/Mview/View.php | 66 +++++-------- .../AdditionalColumnProcessorInterface.php | 39 ++++++++ .../DefaultProcessor.php | 73 +++++++++++++++ .../Mview/View/ChangeLogBatchIterator.php | 44 +++------ .../View/ChangeLogBatchIteratorInterface.php | 8 +- .../Framework/Mview/View/Changelog.php | 47 ++++++---- .../Framework/Mview/View/Subscription.php | 93 +++++++++---------- .../Magento/Framework/Mview/etc/mview.xsd | 18 +++- 12 files changed, 381 insertions(+), 163 deletions(-) create mode 100644 app/code/Magento/Eav/Model/Mview/BatchIterator.php create mode 100644 lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php create mode 100644 lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessors/DefaultProcessor.php diff --git a/app/code/Magento/Eav/Model/Mview/BatchIterator.php b/app/code/Magento/Eav/Model/Mview/BatchIterator.php new file mode 100644 index 0000000000000..b7dd69abd45ff --- /dev/null +++ b/app/code/Magento/Eav/Model/Mview/BatchIterator.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Eav\Mview; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Sql\Expression; +use Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface; +use Magento\Framework\Mview\View\ChangelogInterface; +use Magento\Framework\Mview\View\ChangelogTableNotExistsException; +use Magento\Framework\Phrase; + +/** + * Class BatchIterator + */ +class BatchIterator implements ChangeLogBatchIteratorInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @param ResourceConnection $resourceConnection + */ + public function __construct( + ResourceConnection $resourceConnection + ) { + $this->resourceConnection = $resourceConnection; + } + + /** + * @inheritdoc + */ + public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toVersion, int $batchSize) + { + $connection = $this->resourceConnection->getConnection(); + if (!$connection->isTableExists($changelog->getName())) { + throw new ChangelogTableNotExistsException( + new Phrase("Table %1 does not exist", [$changelog->getName()]) + ); + } + $select = $connection->select()->distinct(true) + ->where( + 'version_id > ?', + (int)$fromVersionId + ) + ->where( + 'version_id <= ?', + $toVersion + ) + ->group([$changelog->getColumnName(), 'store_id']) + ->limit($batchSize); + + $columns = [ + $changelog->getColumnName(), + 'attribute_ids' => new Expression('GROUP_CONCAT(attribute_id)'), + 'store_id' + ]; + + $select->from($changelog->getName(), $columns); + return $connection->fetchAll($select); + } +} diff --git a/lib/internal/Magento/Framework/Mview/Config/Converter.php b/lib/internal/Magento/Framework/Mview/Config/Converter.php index 9cfa84483571c..2737f8db84b7c 100644 --- a/lib/internal/Magento/Framework/Mview/Config/Converter.php +++ b/lib/internal/Magento/Framework/Mview/Config/Converter.php @@ -29,7 +29,7 @@ public function convert($source) $data['action_class'] = $this->getAttributeValue($viewNode, 'class'); $data['group'] = $this->getAttributeValue($viewNode, 'group'); $data['store_scope'] = $this->getAttributeValue($viewNode, 'store_scope'); - $data['attribute_scope'] = $this->getAttributeValue($viewNode, 'attribute_scope'); + $data['iterator'] = $this->getAttributeValue($viewNode, 'iterator'); $data['subscriptions'] = []; /** @var $childNode \DOMNode */ @@ -78,6 +78,7 @@ protected function convertChild(\DOMNode $childNode, $data) $name = $this->getAttributeValue($subscription, 'name'); $column = $this->getAttributeValue($subscription, 'entity_column'); $subscriptionModel = $this->getAttributeValue($subscription, 'subscription_model'); + if (!empty($subscriptionModel) && !in_array( SubscriptionInterface::class, @@ -91,11 +92,36 @@ class_implements(ltrim($subscriptionModel, '\\')) $data['subscriptions'][$name] = [ 'name' => $name, 'column' => $column, - 'subscription_model' => $subscriptionModel + 'subscription_model' => $subscriptionModel, + 'additional_columns' => $this->getAdditionalColumns($subscription), + 'processor' => $this->getAttributeValue($subscription, 'processor') ]; } break; } return $data; } + + /** + * Retrieve additional columns of subscription table + * + * @param \DOMNode $subscription + * @return array + */ + private function getAdditionalColumns(\DOMNode $subscription): array + { + $additionalColumns = []; + foreach ($subscription->childNodes as $childNode) { + if ($childNode->nodeType != XML_ELEMENT_NODE || $childNode->nodeName != 'additionalColumns') { + continue; + } + + $additionalColumns[] = [ + 'name' => $this->getAttributeValue($childNode, 'name'), + 'cl_name' => $this->getAttributeValue($childNode, 'cl_name'), + ]; + } + + return $additionalColumns; + } } diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php index 0a4e8a3840749..2642bf20bc6d6 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php @@ -11,6 +11,7 @@ use Magento\Framework\DB\Adapter\Pdo\Mysql; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\DB\Select; +use Magento\Framework\Mview\Config; use Magento\Framework\Mview\View\Changelog; use Magento\Framework\Mview\View\ChangelogInterface; use PHPUnit\Framework\MockObject\MockObject; @@ -46,7 +47,22 @@ protected function setUp(): void $this->resourceMock = $this->createMock(ResourceConnection::class); $this->mockGetConnection($this->connectionMock); - $this->model = new Changelog($this->resourceMock); + $this->model = new Changelog($this->resourceMock, $this->getMviewConfigMock()); + } + + /** + * @return Config|MockObject + */ + private function getMviewConfigMock() + { + $mviewConfigMock = $this->createMock(Config::class); + $mviewConfigMock->expects($this->any()) + ->method('getView') + ->willReturn([ + 'attribute_scope' => false, + 'store_scope' => false + ]); + return $mviewConfigMock; } public function testInstanceOf() @@ -54,7 +70,7 @@ public function testInstanceOf() $resourceMock = $this->createMock(ResourceConnection::class); $resourceMock->expects($this->once())->method('getConnection')->willReturn(true); - $model = new Changelog($resourceMock); + $model = new Changelog($resourceMock, $this->getMviewConfigMock()); $this->assertInstanceOf(ChangelogInterface::class, $model); } @@ -65,7 +81,7 @@ public function testCheckConnectionException() $resourceMock = $this->createMock(ResourceConnection::class); $resourceMock->expects($this->once())->method('getConnection')->willReturn(null); - $model = new Changelog($resourceMock); + $model = new Changelog($resourceMock, $this->getMviewConfigMock()); $model->setViewId('ViewIdTest'); $this->assertNull($model); } diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php index b91c0b525390f..559309c10c27c 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php @@ -11,6 +11,7 @@ use Magento\Framework\DB\Adapter\Pdo\Mysql; use Magento\Framework\DB\Ddl\Trigger; use Magento\Framework\DB\Ddl\TriggerFactory; +use Magento\Framework\Mview\Config; use Magento\Framework\Mview\View\ChangelogInterface; use Magento\Framework\Mview\View\CollectionInterface; use Magento\Framework\Mview\View\StateInterface; @@ -55,6 +56,10 @@ protected function setUp(): void ->method('quoteIdentifier') ->willReturnArgument(0); + $this->connectionMock->expects($this->any()) + ->method('describeTable') + ->willReturn([]); + $this->resourceMock->expects($this->atLeastOnce()) ->method('getConnection') ->willReturn($this->connectionMock); @@ -78,18 +83,29 @@ protected function setUp(): void true, [] ); - + $this->viewMock->expects($this->any()) + ->method('getId') + ->willReturn(1); $this->resourceMock->expects($this->any()) ->method('getTableName') ->willReturnArgument(0); - + $mviewConfigMock = $this->createMock(Config::class); + $mviewConfigMock->expects($this->any()) + ->method('getView') + ->willReturn([ + 'attribute_scope' => false, + 'store_scope' => false + ]); + $this->mviewConfig = $mviewConfigMock; $this->model = new Subscription( $this->resourceMock, $this->triggerFactoryMock, $this->viewCollectionMock, $this->viewMock, $this->tableName, - 'columnName' + 'columnName', + [], + $mviewConfigMock ); } @@ -122,7 +138,7 @@ public function testCreate() $triggerMock->expects($this->exactly(3)) ->method('setName') ->with($triggerName)->willReturnSelf(); - $triggerMock->expects($this->exactly(3)) + $triggerMock->expects($this->any()) ->method('getName') ->willReturn('triggerName'); $triggerMock->expects($this->exactly(3)) @@ -167,7 +183,7 @@ public function testCreate() true, [] ); - $changelogMock->expects($this->exactly(3)) + $changelogMock->expects($this->any()) ->method('getName') ->willReturn('test_view_cl'); $changelogMock->expects($this->exactly(3)) @@ -191,7 +207,7 @@ public function testCreate() true, [] ); - $otherChangelogMock->expects($this->exactly(3)) + $otherChangelogMock->expects($this->any()) ->method('getName') ->willReturn('other_test_view_cl'); $otherChangelogMock->expects($this->exactly(3)) @@ -217,7 +233,7 @@ public function testCreate() ->method('getChangelog') ->willReturn($otherChangelogMock); - $this->viewMock->expects($this->exactly(3)) + $this->viewMock->expects($this->any()) ->method('getId') ->willReturn('this_id'); $this->viewMock->expects($this->never()) @@ -235,7 +251,6 @@ public function testCreate() $this->connectionMock->expects($this->exactly(3)) ->method('createTrigger') ->with($triggerMock); - $this->model->create(); } @@ -244,7 +259,7 @@ public function testRemove() $triggerMock = $this->createMock(Trigger::class); $triggerMock->expects($this->exactly(3)) ->method('setName')->willReturnSelf(); - $triggerMock->expects($this->exactly(3)) + $triggerMock->expects($this->any()) ->method('getName') ->willReturn('triggerName'); $triggerMock->expects($this->exactly(3)) @@ -271,7 +286,7 @@ public function testRemove() true, [] ); - $otherChangelogMock->expects($this->exactly(3)) + $otherChangelogMock->expects($this->any()) ->method('getName') ->willReturn('other_test_view_cl'); $otherChangelogMock->expects($this->exactly(3)) @@ -297,7 +312,7 @@ public function testRemove() ->method('getChangelog') ->willReturn($otherChangelogMock); - $this->viewMock->expects($this->exactly(3)) + $this->viewMock->expects($this->any()) ->method('getId') ->willReturn('this_id'); $this->viewMock->expects($this->never()) diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index 1ad70aa2c33d3..ac80004068236 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -9,6 +9,7 @@ namespace Magento\Framework\Mview; use InvalidArgumentException; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; use Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface; use Magento\Framework\Mview\View\ChangelogTableNotExistsException; @@ -28,11 +29,6 @@ class View extends DataObject implements ViewInterface */ const DEFAULT_BATCH_SIZE = 1000; - /** - * Max versions to load from database at a time - */ - private static $maxVersionQueryBatch = 100000; - /** * @var string */ @@ -306,52 +302,38 @@ private function executeAction(ActionInterface $action, int $lastVersionId, int $vsFrom = $lastVersionId; while ($vsFrom < $currentVersionId) { - if (isset($this->strategies[$this->changelog->getViewId()])) { - $changelogData = [ - 'name' => $this->changelog->getName(), - 'column_name' => $this->changelog->getColumnName(), - 'view_id' => $this->changelog->getViewId() - ]; - $ids = $this->strategies[$this->changelog->getViewId()]->walk($changelogData, $vsFrom, $batchSize); - $vsFrom += $batchSize; - $action->execute($ids); - } else { - $ids = $this->getBatchOfIds($vsFrom, $currentVersionId); - // We run the actual indexer in batches. - // Chunked AFTER loading to avoid duplicates in separate chunks. - $chunks = array_chunk($ids, $batchSize); - foreach ($chunks as $ids) { - $action->execute($ids); - } - } - + $iterator = $this->createIterator(); + $ids = $iterator->walk($this->getChangelog(), $vsFrom, $currentVersionId, $batchSize); + $vsFrom += $batchSize; + $action->execute($ids); } } /** - * Get batch of entity ids + * Create and validate iterator class for changelog * - * @param int $lastVersionId - * @param int $currentVersionId - * @return array + * @return ChangeLogBatchIteratorInterface|mixed + * @throws Exception */ - private function getBatchOfIds(int &$lastVersionId, int $currentVersionId): array + private function createIterator() { - $ids = []; - $versionBatchSize = self::$maxVersionQueryBatch; - $idsBatchSize = self::$maxVersionQueryBatch; - for ($vsFrom = $lastVersionId; $vsFrom < $currentVersionId; $vsFrom += $versionBatchSize) { - // Don't go past the current version for atomicity. - $versionTo = min($currentVersionId, $vsFrom + $versionBatchSize); - /** To avoid duplicate ids need to flip and merge the array */ - $ids += array_flip($this->getChangelog()->getList($vsFrom, $versionTo)); - $lastVersionId = $versionTo; - if (count($ids) >= $idsBatchSize) { - break; - } + $config = $this->config->getView($this->changelog->getViewId()); + $iteratorClass = $config['iterator']; + + if (!class_exists($iteratorClass)) { + throw new \Exception('Iterator class does not exist for view: ' . $this->changelog->getViewId()); + } + + $iterator = ObjectManager::getInstance()->get($iteratorClass); + + if (!$iterator instanceof ChangeLogBatchIteratorInterface) { + throw new \Exception( + 'Iterator does not implement the right interface for view: ' . + $this->changelog->getViewId() + ); } - return array_keys($ids); + return $iterator; } /** diff --git a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php new file mode 100644 index 0000000000000..6a38437c5a848 --- /dev/null +++ b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Mview\View; + +use Magento\Framework\DB\Ddl\Table; +use Magento\Tests\NamingConvention\true\string; + +interface AdditionalColumnProcessorInterface +{ + /** + * Return triggers columns that should participate in trigger creation + * + * @param string $eventPrefix + * @param array $additionalColumns + * @return array + */ + public function getTriggerColumns(string $eventPrefix, array $additionalColumns): array ; + + /** + * Process column for DDL table + * + * @param Table $table + * @param string $columnName + * @return void + */ + public function processColumnForCLTable(Table $table, string $columnName): void ; + + /** + * Retrieve pre-statement for trigger + * For instance DQL + * + * @return string + */ + public function getPreStatements(): string; +} diff --git a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessors/DefaultProcessor.php b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessors/DefaultProcessor.php new file mode 100644 index 0000000000000..3733e7a9499b3 --- /dev/null +++ b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessors/DefaultProcessor.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Mview\View\AdditionalColumnsProcessor; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Ddl\Table; +use Magento\Framework\Mview\View\AdditionalColumnProcessorInterface; +use Magento\Tests\NamingConvention\true\string; + +class DefaultProcessor implements AdditionalColumnProcessorInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @param ResourceConnection $resourceConnection + */ + public function __construct( + ResourceConnection $resourceConnection + ) { + $this->resourceConnection = $resourceConnection; + } + + /** + * @inheritDoc + */ + public function getTriggerColumns(string $eventPrefix, array $additionalColumns): array + { + $resource = $this->resourceConnection->getConnection(); + $triggersColumns = [ + 'column_names' => [], + 'column_values' => [] + ]; + + foreach ($additionalColumns as $additionalColumn) { + $triggersColumns['column_names'][$additionalColumn['name']] = $resource->quoteIdentifier( + $additionalColumn['cl_name'] + ); + $triggersColumns['column_values'][$additionalColumn['name']] = $eventPrefix . + $resource->quoteIdentifier($additionalColumn['name']); + } + + return $triggersColumns; + } + + /** + * @return string + */ + public function getPreStatements(): string + { + return ''; + } + + /** + * @inheritDoc + */ + public function processColumnForCLTable(Table $table, string $columnName): void + { + $table->addColumn( + $columnName, + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false, 'default' => null], + $columnName + ); + } +} diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php index bc4aff56b941d..9165fc4a0d3cc 100644 --- a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php @@ -8,7 +8,6 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Sql\Expression; -use Magento\Framework\Mview\Config; use Magento\Framework\Phrase; /** @@ -23,56 +22,39 @@ class ChangeLogBatchIterator implements ChangeLogBatchIteratorInterface private $resourceConnection; /** - * @var Config - */ - private $mviewConfig; - - /** - * ChangeLogBatchIterator constructor. * @param ResourceConnection $resourceConnection - * @param Config $mviewConfig */ public function __construct( - ResourceConnection $resourceConnection, - Config $mviewConfig + ResourceConnection $resourceConnection ) { $this->resourceConnection = $resourceConnection; - $this->mviewConfig = $mviewConfig; } /** - * Walk through batches - * - * @param array $changeLogData - * @param $fromVersionId - * @param int $batchSize - * @return mixed - * @throws ChangelogTableNotExistsException + * @inheritdoc */ - public function walk(array $changeLogData, $fromVersionId, int $batchSize) + public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toVersion, int $batchSize) { - $configuration = $this->mviewConfig->getView($changeLogData['view_id']); $connection = $this->resourceConnection->getConnection(); - $changelogTableName = $this->resourceConnection->getTableName($changeLogData['name']); + $changelogTableName = $this->resourceConnection->getTableName($changelog->getName()); + if (!$connection->isTableExists($changelogTableName)) { throw new ChangelogTableNotExistsException(new Phrase("Table %1 does not exist", [$changelogTableName])); } - $columns = [$changeLogData['column_name']]; + $select = $connection->select()->distinct(true) ->where( 'version_id > ?', - (int)$fromVersionId + $fromVersionId + ) + ->where( + 'version_id <= ?', + $toVersion ) - ->group([$changeLogData['column_name'], 'store_id']) + ->group([$changelog->getColumnName()]) ->limit($batchSize); - $columns = [ - $changeLogData['column_name'], - 'attribute_ids' => new Expression('GROUP_CONCAT(attribute_id)'), - 'store_id' - ]; - - $select->from($changelogTableName, $columns); + $select->from($changelogTableName, [$changelog->getColumnName()]); return $connection->fetchAll($select); } } diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php index ec225a24c2963..5e86e0753aec9 100644 --- a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php @@ -20,11 +20,11 @@ interface ChangeLogBatchIteratorInterface /** * Walk through batches * - * @param array $changeLogData - * @param $fromVersionId + * @param ChangelogInterface $changelog + * @param int $fromVersionId + * @param int $lastVersionId * @param int $batchSize * @return mixed - * @throws ChangelogTableNotExistsException */ - public function walk(array $changeLogData, $fromVersionId, int $batchSize); + public function walk(ChangelogInterface $changelog, int $fromVersionId, int $lastVersionId, int $batchSize); } diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index bbfb47807d4d6..3bbd14bf19fbe 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -28,7 +28,7 @@ class Changelog implements ChangelogInterface const COLUMN_NAME = 'entity_id'; /** - * Version ID column name + * Column name for Version ID */ const VERSION_ID_COLUMN_NAME = 'version_id'; @@ -94,7 +94,6 @@ protected function checkConnection() */ public function create() { - $config = $this->mviewConfig->getView($this->getViewId()); $changelogTableName = $this->resource->getTableName($this->getName()); if (!$this->connection->isTableExists($changelogTableName)) { $table = $this->connection->newTable( @@ -113,29 +112,39 @@ public function create() 'Entity ID' ); - if ($config && $config[self::ATTRIBUTE_SCOPE_SUPPORT]) { - $table->addColumn( - self::ATTRIBUTE_COLUMN, - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => true], - 'Attribute ID' - ); - } - if ($config && $config[self::STORE_SCOPE_SUPPORT]) { - $table->addColumn( - self::STORE_COLUMN, - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => true], - 'Store ID' - ); + foreach ($this->initAdditionalColumnData() as $columnData) { + /** @var AdditionalColumnProcessorInterface $processor */ + $processor = $columnData['processor']; + $processor->processColumnForCLTable($table, $columnData['cl_name']); } $this->connection->createTable($table); } } + /** + * Retrieve additional column data + * + * @return array + * @throws \Exception + */ + private function initAdditionalColumnData(): array + { + $config = $this->mviewConfig->getView($this->getViewId()); + $additionalColumns = []; + + foreach ($config['subscriptions'] as $subscription) { + if (isset($subscription['additional_columns'])) { + foreach ($subscription['additional_columns'] as $additionalColumn) { + //We are gatherig unique change log column names in order to create them later + $additionalColumns[$additionalColumn['cl_name']] = $additionalColumn; + } + } + } + + return $additionalColumns; + } + /** * Drop changelog table * diff --git a/lib/internal/Magento/Framework/Mview/View/Subscription.php b/lib/internal/Magento/Framework/Mview/View/Subscription.php index 460db5260f008..e68e928bd9229 100644 --- a/lib/internal/Magento/Framework/Mview/View/Subscription.php +++ b/lib/internal/Magento/Framework/Mview/View/Subscription.php @@ -80,10 +80,10 @@ class Subscription implements SubscriptionInterface * @param \Magento\Framework\DB\Ddl\TriggerFactory $triggerFactory * @param \Magento\Framework\Mview\View\CollectionInterface $viewCollection * @param \Magento\Framework\Mview\ViewInterface $view - * @param Config $mviewConfig * @param string $tableName * @param string $columnName * @param array $ignoredUpdateColumns + * @param Config|null $mviewConfig */ public function __construct( ResourceConnection $resource, @@ -207,7 +207,9 @@ protected function getLinkedViews() */ protected function buildStatement($event, $changelog) { - $trigger = "INSERT IGNORE INTO %s (%s) VALUES (%s);"; + $processor = $this->getProcessor(); + $prefix = $event === Trigger::EVENT_DELETE ? 'OLD.' : 'NEW.'; + $trigger = "%sINSERT IGNORE INTO %s (%s) VALUES (%s);"; switch ($event) { case Trigger::EVENT_UPDATE: $tableName = $this->resource->getTableName($this->getTableName()); @@ -233,67 +235,60 @@ protected function buildStatement($event, $changelog) } break; } - list($columnNames, $columnValues) = $this->prepareTriggerBody($changelog, $event); + + $columns = [ + 'column_names' => [ + 'entity_id' => $this->connection->quoteIdentifier($changelog->getColumnName()) + ], + 'column_values' => [ + 'entity_id' => $this->getEntityColumn($prefix) + ] + ]; + + if (isset($subscriptionData['additional_columns'])) { + $columns = array_replace_recursive( + $columns, + $processor->getTriggerColumns($prefix, $subscriptionData['additional_columns']) + ); + } + return sprintf( $trigger, + $processor->getPreStatements(), $this->connection->quoteIdentifier($this->resource->getTableName($changelog->getName())), - $columnNames, - $columnValues + implode(", " , $columns['column_names']), + implode(", ", $columns['column_values']) ); } /** - * @param string $prefix - * @return string + * Instantiate and retrieve additional columns processor + * + * @return AdditionalColumnProcessorInterface + * @throws \Exception */ - public function getEntityColumn(string $prefix): string + private function getProcessor(): AdditionalColumnProcessorInterface { - return $prefix . $this->connection->quoteIdentifier($this->getColumnName()); + $subscriptionData = $this->mviewConfig->getView($this->getView()->getId())['subscriptions']; + $processorClass = $subscriptionData['processor']; + $processor = ObjectManager::getInstance()->get($processorClass); + + if (!$processor instanceof AdditionalColumnProcessorInterface) { + throw new \Exception( + 'Processor should implements ' . AdditionalColumnProcessorInterface::class + ); + } + + return $processor; } /** - * Prepare column names and column values for trigger body - * - * @param ChangelogInterface $changelog - * @param string $eventType - * @return array + * @param string $prefix + * @return string */ - public function prepareTriggerBody(ChangelogInterface $changelog, string $eventType) + public function getEntityColumn(string $prefix): string { - $prefix = $eventType === Trigger::EVENT_DELETE ? 'OLD.' : 'NEW.'; - $describedSubscribedColumns = array_column( - $this->connection->describeTable($this->getTableName()), - 'COLUMN_NAME' - ); - $describedClColumns = array_column( - $this->connection->describeTable($changelog->getName()), - 'COLUMN_NAME' - ); - $viewConfig = $this->mviewConfig->getView($this->getView()->getId()); - $columnNames = [$this->connection->quoteIdentifier($changelog->getColumnName())]; - $columnValues = [$this->getEntityColumn($prefix)]; - //If we need to add attributes - if ($viewConfig[ChangelogInterface::ATTRIBUTE_SCOPE_SUPPORT] && - array_search(Changelog::ATTRIBUTE_COLUMN, $describedSubscribedColumns) && - array_search(Changelog::ATTRIBUTE_COLUMN, $describedClColumns) - - ) { - $columnValues[] = $prefix . $this->connection->quoteIdentifier(Changelog::ATTRIBUTE_COLUMN); - $columnNames[] = $this->connection->quoteIdentifier(Changelog::ATTRIBUTE_COLUMN); - } - //If we need to add stores - if ($viewConfig[ChangelogInterface::STORE_SCOPE_SUPPORT] && - array_search(Changelog::STORE_COLUMN, $describedSubscribedColumns) && - array_search(Changelog::STORE_COLUMN, $describedClColumns) - ) { - $columnValues[] = $prefix . $this->connection->quoteIdentifier(Changelog::STORE_COLUMN); - $columnNames[] = $this->connection->quoteIdentifier(Changelog::STORE_COLUMN); - } - - return [ - implode(",", $columnNames), - implode(",", $columnValues) - ]; + return $prefix . $this->connection->quoteIdentifier($this->getColumnName()); } /** diff --git a/lib/internal/Magento/Framework/Mview/etc/mview.xsd b/lib/internal/Magento/Framework/Mview/etc/mview.xsd index 5b264efdf5445..ada98d87d5ca3 100644 --- a/lib/internal/Magento/Framework/Mview/etc/mview.xsd +++ b/lib/internal/Magento/Framework/Mview/etc/mview.xsd @@ -46,8 +46,7 @@ <xs:attribute name="id" type="xs:string" use="required" /> <xs:attribute name="class" type="classType" use="required" /> <xs:attribute name="group" type="xs:string" use="required" /> - <xs:attribute name="store_scope" type="xs:boolean" use="optional" /> - <xs:attribute name="attribute_scope" type="xs:boolean" use="optional" /> + <xs:attribute name="iterator" type="classType" default="Magento\Framework\Mview\View\LegacyChangeLogBatchIterator" /> </xs:complexType> <xs:simpleType name="classType"> @@ -78,9 +77,24 @@ Table declaration. </xs:documentation> </xs:annotation> + <xs:sequence> + <xs:element minOccurs="0" name="additionalColumns" type="additionalColumnsType" /> + </xs:sequence> <xs:attribute name="name" type="tableNameType" use="required" /> <xs:attribute name="entity_column" type="entityColumnType" use="required" /> <xs:attribute name="subscription_model" type="subscriptionModelType" /> + <xs:attribute name="processor" type="classType" default="Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor" /> + </xs:complexType> + + <xs:complexType name="additionalColumnsType"> + <xs:sequence> + <xs:element minOccurs="1" maxOccurs="unbounded" name="column" type="additionalColumnAttributeType" /> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="additionalColumnAttributeType"> + <xs:attribute name="name" type="xs:string" /> + <xs:attribute name="cl_name" type="xs:string" /> </xs:complexType> <xs:simpleType name="entityColumnType"> From b1a759237f1b3030ff47483cbd2eb6732207d449 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 17 Sep 2020 15:12:11 +0300 Subject: [PATCH 043/346] Mview patch update -- move framework logic to saas-export --- .../Framework/Mview/Config/Converter.php | 42 ++++++++++++-- .../AdditionalColumnProcessorInterface.php | 1 - .../DefaultProcessor.php | 11 ++-- .../Framework/Mview/View/Changelog.php | 5 +- .../Framework/Mview/View/Subscription.php | 56 ++++++++++++------- .../Magento/Framework/Mview/etc/mview.xsd | 1 + 6 files changed, 83 insertions(+), 33 deletions(-) rename lib/internal/Magento/Framework/Mview/View/{AdditionalColumnsProcessors => AdditionalColumnsProcessor}/DefaultProcessor.php (83%) diff --git a/lib/internal/Magento/Framework/Mview/Config/Converter.php b/lib/internal/Magento/Framework/Mview/Config/Converter.php index 2737f8db84b7c..f63766d729d5d 100644 --- a/lib/internal/Magento/Framework/Mview/Config/Converter.php +++ b/lib/internal/Magento/Framework/Mview/Config/Converter.php @@ -5,10 +5,34 @@ */ namespace Magento\Framework\Mview\Config; +use Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor; +use Magento\Framework\Mview\View\ChangeLogBatchIterator; use Magento\Framework\Mview\View\SubscriptionInterface; class Converter implements \Magento\Framework\Config\ConverterInterface { + /** + * @var string + */ + private $defaultProcessor; + + /** + * @var string + */ + private $defaultIterator; + + /** + * @param string $defaultProcessor + * @param string $defaultIterator + */ + public function __construct( + string $defaultProcessor = DefaultProcessor::class, + string $defaultIterator = ChangeLogBatchIterator::class + ) { + $this->defaultProcessor = $defaultProcessor; + $this->defaultIterator = $defaultIterator; + } + /** * Convert dom node tree to array * @@ -29,7 +53,7 @@ public function convert($source) $data['action_class'] = $this->getAttributeValue($viewNode, 'class'); $data['group'] = $this->getAttributeValue($viewNode, 'group'); $data['store_scope'] = $this->getAttributeValue($viewNode, 'store_scope'); - $data['iterator'] = $this->getAttributeValue($viewNode, 'iterator'); + $data['iterator'] = $this->getAttributeValue($viewNode, 'iterator') ?: $this->defaultIterator; $data['subscriptions'] = []; /** @var $childNode \DOMNode */ @@ -95,6 +119,7 @@ class_implements(ltrim($subscriptionModel, '\\')) 'subscription_model' => $subscriptionModel, 'additional_columns' => $this->getAdditionalColumns($subscription), 'processor' => $this->getAttributeValue($subscription, 'processor') + ?: $this->defaultProcessor ]; } break; @@ -116,10 +141,17 @@ private function getAdditionalColumns(\DOMNode $subscription): array continue; } - $additionalColumns[] = [ - 'name' => $this->getAttributeValue($childNode, 'name'), - 'cl_name' => $this->getAttributeValue($childNode, 'cl_name'), - ]; + foreach ($childNode->childNodes as $columnNode) { + if ($columnNode->nodeName !== 'column') { + continue; + } + + $additionalColumns[$this->getAttributeValue($columnNode, 'name')] = [ + 'name' => $this->getAttributeValue($columnNode, 'name'), + 'cl_name' => $this->getAttributeValue($columnNode, 'cl_name'), + 'constant' => $this->getAttributeValue($columnNode, 'constant'), + ]; + } } return $additionalColumns; diff --git a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php index 6a38437c5a848..c89fbce074a13 100644 --- a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php +++ b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnProcessorInterface.php @@ -7,7 +7,6 @@ namespace Magento\Framework\Mview\View; use Magento\Framework\DB\Ddl\Table; -use Magento\Tests\NamingConvention\true\string; interface AdditionalColumnProcessorInterface { diff --git a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessors/DefaultProcessor.php b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php similarity index 83% rename from lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessors/DefaultProcessor.php rename to lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php index 3733e7a9499b3..96d9865998131 100644 --- a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessors/DefaultProcessor.php +++ b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php @@ -9,7 +9,6 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\Mview\View\AdditionalColumnProcessorInterface; -use Magento\Tests\NamingConvention\true\string; class DefaultProcessor implements AdditionalColumnProcessorInterface { @@ -42,8 +41,10 @@ public function getTriggerColumns(string $eventPrefix, array $additionalColumns) $triggersColumns['column_names'][$additionalColumn['name']] = $resource->quoteIdentifier( $additionalColumn['cl_name'] ); - $triggersColumns['column_values'][$additionalColumn['name']] = $eventPrefix . - $resource->quoteIdentifier($additionalColumn['name']); + + $triggersColumns['column_values'][$additionalColumn['name']] = isset($additionalColumn['constant']) ? + $resource->quote($additionalColumn['constant']) : + $eventPrefix . $resource->quoteIdentifier($additionalColumn['name']); } return $triggersColumns; @@ -64,9 +65,9 @@ public function processColumnForCLTable(Table $table, string $columnName): void { $table->addColumn( $columnName, - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, null, - ['unsigned' => true, 'nullable' => false, 'default' => null], + ['unsigned' => true, 'nullable' => true, 'default' => null], $columnName ); } diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index 3bbd14bf19fbe..df4e55fe54850 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -6,6 +6,7 @@ namespace Magento\Framework\Mview\View; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Adapter\ConnectionException; use Magento\Framework\DB\Sql\Expression; use Magento\Framework\Exception\RuntimeException; @@ -114,7 +115,8 @@ public function create() foreach ($this->initAdditionalColumnData() as $columnData) { /** @var AdditionalColumnProcessorInterface $processor */ - $processor = $columnData['processor']; + $processorClass = $columnData['processor']; + $processor = ObjectManager::getInstance()->get($processorClass); $processor->processColumnForCLTable($table, $columnData['cl_name']); } @@ -138,6 +140,7 @@ private function initAdditionalColumnData(): array foreach ($subscription['additional_columns'] as $additionalColumn) { //We are gatherig unique change log column names in order to create them later $additionalColumns[$additionalColumn['cl_name']] = $additionalColumn; + $additionalColumns[$additionalColumn['cl_name']]['processor'] = $subscription['processor']; } } } diff --git a/lib/internal/Magento/Framework/Mview/View/Subscription.php b/lib/internal/Magento/Framework/Mview/View/Subscription.php index e68e928bd9229..79d31e2a76d69 100644 --- a/lib/internal/Magento/Framework/Mview/View/Subscription.php +++ b/lib/internal/Magento/Framework/Mview/View/Subscription.php @@ -198,6 +198,38 @@ protected function getLinkedViews() return $this->linkedViews; } + /** + * Prepare columns for trigger statement. Should be protected in order to serve new approach + * + * @param ChangelogInterface $changelog + * @param string $event + * @return array + * @throws \Exception + */ + protected function prepareColumns(ChangelogInterface $changelog, string $event): array + { + $prefix = $event === Trigger::EVENT_DELETE ? 'OLD.' : 'NEW.'; + $subscriptionData = $this->mviewConfig->getView($changelog->getViewId())['subscriptions'][$this->getTableName()]; + $columns = [ + 'column_names' => [ + 'entity_id' => $this->connection->quoteIdentifier($changelog->getColumnName()) + ], + 'column_values' => [ + 'entity_id' => $this->getEntityColumn($prefix) + ] + ]; + + if (!empty($subscriptionData['additional_columns'])) { + $processor = $this->getProcessor(); + $columns = array_replace_recursive( + $columns, + $processor->getTriggerColumns($prefix, $subscriptionData['additional_columns']) + ); + } + + return $columns; + } + /** * Build trigger statement for INSERT, UPDATE, DELETE events * @@ -207,8 +239,6 @@ protected function getLinkedViews() */ protected function buildStatement($event, $changelog) { - $processor = $this->getProcessor(); - $prefix = $event === Trigger::EVENT_DELETE ? 'OLD.' : 'NEW.'; $trigger = "%sINSERT IGNORE INTO %s (%s) VALUES (%s);"; switch ($event) { case Trigger::EVENT_UPDATE: @@ -235,26 +265,10 @@ protected function buildStatement($event, $changelog) } break; } - - $columns = [ - 'column_names' => [ - 'entity_id' => $this->connection->quoteIdentifier($changelog->getColumnName()) - ], - 'column_values' => [ - 'entity_id' => $this->getEntityColumn($prefix) - ] - ]; - - if (isset($subscriptionData['additional_columns'])) { - $columns = array_replace_recursive( - $columns, - $processor->getTriggerColumns($prefix, $subscriptionData['additional_columns']) - ); - } - + $columns = $this->prepareColumns($changelog, $event); return sprintf( $trigger, - $processor->getPreStatements(), + $this->getProcessor()->getPreStatements(), $this->connection->quoteIdentifier($this->resource->getTableName($changelog->getName())), implode(", " , $columns['column_names']), implode(", ", $columns['column_values']) @@ -270,7 +284,7 @@ protected function buildStatement($event, $changelog) private function getProcessor(): AdditionalColumnProcessorInterface { $subscriptionData = $this->mviewConfig->getView($this->getView()->getId())['subscriptions']; - $processorClass = $subscriptionData['processor']; + $processorClass = $subscriptionData[$this->getTableName()]['processor']; $processor = ObjectManager::getInstance()->get($processorClass); if (!$processor instanceof AdditionalColumnProcessorInterface) { diff --git a/lib/internal/Magento/Framework/Mview/etc/mview.xsd b/lib/internal/Magento/Framework/Mview/etc/mview.xsd index ada98d87d5ca3..053d1b2853f66 100644 --- a/lib/internal/Magento/Framework/Mview/etc/mview.xsd +++ b/lib/internal/Magento/Framework/Mview/etc/mview.xsd @@ -95,6 +95,7 @@ <xs:complexType name="additionalColumnAttributeType"> <xs:attribute name="name" type="xs:string" /> <xs:attribute name="cl_name" type="xs:string" /> + <xs:attribute name="constant" type="xs:string" /> </xs:complexType> <xs:simpleType name="entityColumnType"> From 7237a30eaa00c12008bc159f034bfcd07c183193 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 17 Sep 2020 17:47:32 +0300 Subject: [PATCH 044/346] Mview patch update -- move framework logic to saas-export --- .../Magento/Framework/Mview/View/ChangeLogBatchIterator.php | 2 +- lib/internal/Magento/Framework/Mview/View/Changelog.php | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php index 9165fc4a0d3cc..f3ae87b847cb1 100644 --- a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php @@ -55,6 +55,6 @@ public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toV ->limit($batchSize); $select->from($changelogTableName, [$changelog->getColumnName()]); - return $connection->fetchAll($select); + return $connection->fetchCol($select); } } diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index df4e55fe54850..94ce4c19874ce 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -135,6 +135,10 @@ private function initAdditionalColumnData(): array $config = $this->mviewConfig->getView($this->getViewId()); $additionalColumns = []; + if (!$config) { + return $additionalColumns; + } + foreach ($config['subscriptions'] as $subscription) { if (isset($subscription['additional_columns'])) { foreach ($subscription['additional_columns'] as $additionalColumn) { From 99133052528df4752db1f582bb79e3c83250db46 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 17 Sep 2020 18:31:16 +0300 Subject: [PATCH 045/346] Mview patch update -- move framework logic to saas-export --- .../Framework/Mview/Config/Converter.php | 1 - .../Mview/Test/Unit/View/ChangelogTest.php | 3 +- .../Mview/Test/Unit/View/SubscriptionTest.php | 15 +++++-- .../Framework/Mview/Test/Unit/ViewTest.php | 41 +++++++++++-------- .../Mview/Test/Unit/_files/mview_config.php | 9 +++- lib/internal/Magento/Framework/Mview/View.php | 23 +++++++---- 6 files changed, 60 insertions(+), 32 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/Config/Converter.php b/lib/internal/Magento/Framework/Mview/Config/Converter.php index f63766d729d5d..bb15287f9482a 100644 --- a/lib/internal/Magento/Framework/Mview/Config/Converter.php +++ b/lib/internal/Magento/Framework/Mview/Config/Converter.php @@ -52,7 +52,6 @@ public function convert($source) $data['view_id'] = $viewId; $data['action_class'] = $this->getAttributeValue($viewNode, 'class'); $data['group'] = $this->getAttributeValue($viewNode, 'group'); - $data['store_scope'] = $this->getAttributeValue($viewNode, 'store_scope'); $data['iterator'] = $this->getAttributeValue($viewNode, 'iterator') ?: $this->defaultIterator; $data['subscriptions'] = []; diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php index 2642bf20bc6d6..4af3f65be6883 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php @@ -59,8 +59,7 @@ private function getMviewConfigMock() $mviewConfigMock->expects($this->any()) ->method('getView') ->willReturn([ - 'attribute_scope' => false, - 'store_scope' => false + 'subscriptions' => [] ]); return $mviewConfigMock; } diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php index 559309c10c27c..2178009eda436 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php @@ -7,11 +7,13 @@ namespace Magento\Framework\Mview\Test\Unit\View; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\Pdo\Mysql; use Magento\Framework\DB\Ddl\Trigger; use Magento\Framework\DB\Ddl\TriggerFactory; use Magento\Framework\Mview\Config; +use Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor; use Magento\Framework\Mview\View\ChangelogInterface; use Magento\Framework\Mview\View\CollectionInterface; use Magento\Framework\Mview\View\StateInterface; @@ -49,6 +51,7 @@ class SubscriptionTest extends TestCase protected function setUp(): void { + $this->tableName = 'test_table'; $this->connectionMock = $this->createMock(Mysql::class); $this->resourceMock = $this->createMock(ResourceConnection::class); @@ -63,7 +66,10 @@ protected function setUp(): void $this->resourceMock->expects($this->atLeastOnce()) ->method('getConnection') ->willReturn($this->connectionMock); - + ObjectManager::getInstance()->expects($this->any()) + ->method('get') + ->with(DefaultProcessor::class) + ->willReturn(2); $this->triggerFactoryMock = $this->createMock(TriggerFactory::class); $this->viewCollectionMock = $this->getMockForAbstractClass( CollectionInterface::class, @@ -93,8 +99,11 @@ protected function setUp(): void $mviewConfigMock->expects($this->any()) ->method('getView') ->willReturn([ - 'attribute_scope' => false, - 'store_scope' => false + 'subscriptions' => [ + $this->tableName => [ + 'processor' => DefaultProcessor::class + ] + ] ]); $this->mviewConfig = $mviewConfigMock; $this->model = new Subscription( diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php index 7d69ff43f158b..8d460ac99a46b 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/ViewTest.php @@ -7,6 +7,7 @@ namespace Magento\Framework\Mview\Test\Unit; +use Laminas\Log\Filter\Mock; use Magento\Framework\Mview\ActionFactory; use Magento\Framework\Mview\ActionInterface; use Magento\Framework\Mview\ConfigInterface; @@ -53,6 +54,11 @@ class ViewTest extends TestCase */ protected $subscriptionFactoryMock; + /** + * @var MockObject|View\ChangeLogBatchIteratorInterface + */ + private $iteratorMock; + /** * @inheritdoc */ @@ -67,6 +73,7 @@ protected function setUp(): void true, ['getView'] ); + $this->iteratorMock = $this->createMock(View\ChangeLogBatchIteratorInterface::class); $this->actionFactoryMock = $this->createPartialMock(ActionFactory::class, ['get']); $this->stateMock = $this->createPartialMock( State::class, @@ -97,7 +104,10 @@ protected function setUp(): void $this->actionFactoryMock, $this->stateMock, $this->changelogMock, - $this->subscriptionFactoryMock + $this->subscriptionFactoryMock, + [], + [], + $this->iteratorMock ); } @@ -334,7 +344,7 @@ public function testUpdate() $currentVersionId ); $this->changelogMock->expects( - $this->once() + $this->any() )->method( 'getList' )->with( @@ -345,6 +355,7 @@ public function testUpdate() ); $actionMock = $this->getMockForAbstractClass(ActionInterface::class); + $this->iteratorMock->expects($this->once())->method('walk')->willReturn($listId); $actionMock->expects($this->once())->method('execute')->with($listId)->willReturnSelf(); $this->actionFactoryMock->expects( $this->once() @@ -390,7 +401,7 @@ public function testUpdateEx(): void ->expects($this->once()) ->method('getVersion') ->willReturn($currentVersionId); - + $this->iteratorMock->expects($this->any())->method('walk')->willReturn($this->generateChangeLog(150, 1, 150)); $this->changelogMock->method('getList') ->willReturnMap( [ @@ -401,7 +412,7 @@ public function testUpdateEx(): void ); $actionMock = $this->getMockForAbstractClass(ActionInterface::class); - $actionMock->expects($this->once()) + $actionMock->expects($this->any()) ->method('execute') ->with($this->generateChangeLog(150, 1, 150)) ->willReturnSelf(); @@ -457,7 +468,7 @@ public function testUpdateWithException() $this->stateMock->expects($this->atLeastOnce()) ->method('getMode') ->willReturn(StateInterface::MODE_ENABLED); - $this->stateMock->expects($this->exactly(2)) + $this->stateMock->expects($this->any()) ->method('getStatus') ->willReturn(StateInterface::STATUS_IDLE); $this->stateMock->expects($this->exactly(2)) @@ -472,16 +483,9 @@ public function testUpdateWithException() )->willReturn( $currentVersionId ); - $this->changelogMock->expects( - $this->once() - )->method( - 'getList' - )->with( - $lastVersionId, - $currentVersionId - )->willReturn( - $listId - ); + $this->iteratorMock->expects($this->any()) + ->method('walk') + ->willReturn([2,3]); $actionMock = $this->createPartialMock(ActionInterface::class, ['execute']); $actionMock->expects($this->once())->method('execute')->with($listId)->willReturnCallback( @@ -767,8 +771,11 @@ public function testGetUpdated() protected function loadView() { $viewId = 'view_test'; + $this->changelogMock->expects($this->any()) + ->method('getViewId') + ->willReturn($viewId); $this->configMock->expects( - $this->once() + $this->any() )->method( 'getView' )->with( @@ -788,7 +795,7 @@ protected function getViewData() 'view_id' => 'view_test', 'action_class' => 'Some\Class\Name', 'group' => 'some_group', - 'subscriptions' => ['some_entity' => ['name' => 'some_entity', 'column' => 'entity_id']] + 'subscriptions' => ['some_entity' => ['name' => 'some_entity', 'column' => 'entity_id']], ]; } } diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php index a19f90546bac3..36e7dca899047 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php @@ -20,14 +20,19 @@ 'some_entity' => [ 'name' => 'some_entity', 'column' => 'entity_id', - 'subscription_model' => null + 'subscription_model' => null, + 'additional_columns' => [], + 'processor' => \Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor::class ], 'some_product_relation' => [ 'name' => 'some_product_relation', 'column' => 'product_id', - 'subscription_model' => null + 'subscription_model' => null, + 'additional_columns' => [], + 'processor' => \Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor::class ], ], + 'iterator' => \Magento\Framework\Mview\View\ChangeLogBatchIterator::class ], ] ]; diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index ac80004068236..fe8f4c675284b 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -11,6 +11,7 @@ use InvalidArgumentException; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; +use Magento\Framework\Mview\View\ChangeLogBatchIterator; use Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface; use Magento\Framework\Mview\View\ChangelogTableNotExistsException; use Magento\Framework\Mview\View\SubscriptionFactory; @@ -65,9 +66,9 @@ class View extends DataObject implements ViewInterface private $changelogBatchSize; /** - * @var ChangeLogBatchIteratorInterface[] + * @var ChangeLogBatchIteratorInterface */ - private $strategies; + private $iterator; /** * @param ConfigInterface $config @@ -77,7 +78,7 @@ class View extends DataObject implements ViewInterface * @param SubscriptionFactory $subscriptionFactory * @param array $data * @param array $changelogBatchSize - * @param array $strategies + * @param ChangeLogBatchIteratorInterface|null $changeLogBatchIterator */ public function __construct( ConfigInterface $config, @@ -87,7 +88,7 @@ public function __construct( SubscriptionFactory $subscriptionFactory, array $data = [], array $changelogBatchSize = [], - array $strategies = [] + ChangeLogBatchIteratorInterface $changeLogBatchIterator = null ) { $this->config = $config; $this->actionFactory = $actionFactory; @@ -96,7 +97,7 @@ public function __construct( $this->subscriptionFactory = $subscriptionFactory; $this->changelogBatchSize = $changelogBatchSize; parent::__construct($data); - $this->strategies = $strategies; + $this->iterator = $changeLogBatchIterator; } /** @@ -302,8 +303,12 @@ private function executeAction(ActionInterface $action, int $lastVersionId, int $vsFrom = $lastVersionId; while ($vsFrom < $currentVersionId) { - $iterator = $this->createIterator(); + $iterator = $this->getIterator(); $ids = $iterator->walk($this->getChangelog(), $vsFrom, $currentVersionId, $batchSize); + + if (empty($ids)) { + break; + } $vsFrom += $batchSize; $action->execute($ids); } @@ -315,8 +320,12 @@ private function executeAction(ActionInterface $action, int $lastVersionId, int * @return ChangeLogBatchIteratorInterface|mixed * @throws Exception */ - private function createIterator() + private function getIterator() { + if ($this->iterator) { + return $this->iterator; + } + $config = $this->config->getView($this->changelog->getViewId()); $iteratorClass = $config['iterator']; From e4a2d3cdd2a1d427a35009c89b52fe570aba2847 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Mon, 21 Sep 2020 16:10:11 +0300 Subject: [PATCH 046/346] Mview patch update proposal --- .../Magento/Eav/Model/Mview/BatchIterator.php | 67 ---------- .../Eav/Model/Mview/ChangeLogBatchWalker.php | 120 ++++++++++++++++++ .../Framework/Mview/Config/Converter.php | 6 +- lib/internal/Magento/Framework/Mview/View.php | 47 +++---- .../ProcessorFactory.php | 38 ++++++ ...hIterator.php => ChangeLogBatchWalker.php} | 5 +- .../View/ChangeLogBatchWalkerFactory.php | 37 ++++++ ....php => ChangeLogBatchWalkerInterface.php} | 4 +- .../Framework/Mview/View/Changelog.php | 13 +- .../Magento/Framework/Mview/etc/mview.xsd | 2 +- 10 files changed, 229 insertions(+), 110 deletions(-) delete mode 100644 app/code/Magento/Eav/Model/Mview/BatchIterator.php create mode 100644 app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php create mode 100644 lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/ProcessorFactory.php rename lib/internal/Magento/Framework/Mview/View/{ChangeLogBatchIterator.php => ChangeLogBatchWalker.php} (89%) create mode 100644 lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalkerFactory.php rename lib/internal/Magento/Framework/Mview/View/{ChangeLogBatchIteratorInterface.php => ChangeLogBatchWalkerInterface.php} (84%) diff --git a/app/code/Magento/Eav/Model/Mview/BatchIterator.php b/app/code/Magento/Eav/Model/Mview/BatchIterator.php deleted file mode 100644 index b7dd69abd45ff..0000000000000 --- a/app/code/Magento/Eav/Model/Mview/BatchIterator.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Eav\Mview; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Sql\Expression; -use Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface; -use Magento\Framework\Mview\View\ChangelogInterface; -use Magento\Framework\Mview\View\ChangelogTableNotExistsException; -use Magento\Framework\Phrase; - -/** - * Class BatchIterator - */ -class BatchIterator implements ChangeLogBatchIteratorInterface -{ - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @param ResourceConnection $resourceConnection - */ - public function __construct( - ResourceConnection $resourceConnection - ) { - $this->resourceConnection = $resourceConnection; - } - - /** - * @inheritdoc - */ - public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toVersion, int $batchSize) - { - $connection = $this->resourceConnection->getConnection(); - if (!$connection->isTableExists($changelog->getName())) { - throw new ChangelogTableNotExistsException( - new Phrase("Table %1 does not exist", [$changelog->getName()]) - ); - } - $select = $connection->select()->distinct(true) - ->where( - 'version_id > ?', - (int)$fromVersionId - ) - ->where( - 'version_id <= ?', - $toVersion - ) - ->group([$changelog->getColumnName(), 'store_id']) - ->limit($batchSize); - - $columns = [ - $changelog->getColumnName(), - 'attribute_ids' => new Expression('GROUP_CONCAT(attribute_id)'), - 'store_id' - ]; - - $select->from($changelog->getName(), $columns); - return $connection->fetchAll($select); - } -} diff --git a/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php b/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php new file mode 100644 index 0000000000000..fdc71faa90902 --- /dev/null +++ b/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php @@ -0,0 +1,120 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Eav\Model\Mview; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Sql\Expression; +use Magento\Framework\Mview\View\ChangeLogBatchWalkerInterface; +use Magento\Framework\Mview\View\ChangelogInterface; + +/** + * Class BatchIterator + */ +class ChangeLogBatchWalker implements ChangeLogBatchWalkerInterface +{ + private const GROUP_CONCAT_MAX_VARIABLE = 'group_concat_max_len'; + /** ID is defined as small int. Default size of it is 5 */ + private const DEFAULT_ID_SIZE = 5; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var array + */ + private $entityTypeCodes; + + /** + * @param ResourceConnection $resourceConnection + * @param array $entityTypeCodes + */ + public function __construct( + ResourceConnection $resourceConnection, + array $entityTypeCodes = [] + ) { + $this->resourceConnection = $resourceConnection; + $this->entityTypeCodes = $entityTypeCodes; + } + + /** + * Calculate EAV attributes size + * + * @param ChangelogInterface $changelog + * @return int + * @throws \Exception + */ + private function calculateEavAttributeSize(ChangelogInterface $changelog): int + { + $connection = $this->resourceConnection->getConnection(); + + if (!isset($this->entityTypeCodes[$changelog->getViewId()])) { + throw new \Exception('Entity type for view was not defined'); + } + + $select = $connection->select(); + $select->from( + $this->resourceConnection->getTableName('eav_attribute'), + new Expression('COUNT(*)') + ) + ->joinInner( + ['type' => $connection->getTableName('eav_entity_type')], + 'type.entity_type_id=eav_attribute.entity_type_id' + ) + ->where('type.entity_type_code = ?', $this->entityTypeCodes[$changelog->getViewId()]); + + return (int) $connection->fetchOne($select); + } + + /** + * Prepare group max concat + * + * @param int $numberOfAttributes + * @return void + * @throws \Exception + */ + private function setGroupConcatMax(int $numberOfAttributes): void + { + $connection = $this->resourceConnection->getConnection(); + $connection->query(sprintf( + 'SET SESSION %s=%s', + self::GROUP_CONCAT_MAX_VARIABLE, + $numberOfAttributes * (self::DEFAULT_ID_SIZE + 1) + )); + } + + /** + * @inheritdoc + * @throws \Exception + */ + public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toVersion, int $batchSize) + { + $connection = $this->resourceConnection->getConnection(); + $numberOfAttributes = $this->calculateEavAttributeSize($changelog); + $this->setGroupConcatMax($numberOfAttributes); + $select = $connection->select()->distinct(true) + ->where( + 'version_id > ?', + (int) $fromVersionId + ) + ->where( + 'version_id <= ?', + $toVersion + ) + ->group([$changelog->getColumnName(), 'store_id']) + ->limit($batchSize); + + $columns = [ + $changelog->getColumnName(), + 'attribute_ids' => new Expression('GROUP_CONCAT(attribute_id)'), + 'store_id' + ]; + $select->from($changelog->getName(), $columns); + return $connection->fetchAll($select); + } +} diff --git a/lib/internal/Magento/Framework/Mview/Config/Converter.php b/lib/internal/Magento/Framework/Mview/Config/Converter.php index bb15287f9482a..988cffa8b7ce2 100644 --- a/lib/internal/Magento/Framework/Mview/Config/Converter.php +++ b/lib/internal/Magento/Framework/Mview/Config/Converter.php @@ -6,7 +6,7 @@ namespace Magento\Framework\Mview\Config; use Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor; -use Magento\Framework\Mview\View\ChangeLogBatchIterator; +use Magento\Framework\Mview\View\ChangeLogBatchWalker; use Magento\Framework\Mview\View\SubscriptionInterface; class Converter implements \Magento\Framework\Config\ConverterInterface @@ -27,7 +27,7 @@ class Converter implements \Magento\Framework\Config\ConverterInterface */ public function __construct( string $defaultProcessor = DefaultProcessor::class, - string $defaultIterator = ChangeLogBatchIterator::class + string $defaultIterator = ChangeLogBatchWalker::class ) { $this->defaultProcessor = $defaultProcessor; $this->defaultIterator = $defaultIterator; @@ -52,7 +52,7 @@ public function convert($source) $data['view_id'] = $viewId; $data['action_class'] = $this->getAttributeValue($viewNode, 'class'); $data['group'] = $this->getAttributeValue($viewNode, 'group'); - $data['iterator'] = $this->getAttributeValue($viewNode, 'iterator') ?: $this->defaultIterator; + $data['walker'] = $this->getAttributeValue($viewNode, 'walker') ?: $this->defaultIterator; $data['subscriptions'] = []; /** @var $childNode \DOMNode */ diff --git a/lib/internal/Magento/Framework/Mview/View.php b/lib/internal/Magento/Framework/Mview/View.php index fe8f4c675284b..420702c434103 100644 --- a/lib/internal/Magento/Framework/Mview/View.php +++ b/lib/internal/Magento/Framework/Mview/View.php @@ -11,8 +11,8 @@ use InvalidArgumentException; use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; -use Magento\Framework\Mview\View\ChangeLogBatchIterator; -use Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface; +use Magento\Framework\Mview\View\ChangeLogBatchWalkerFactory; +use Magento\Framework\Mview\View\ChangeLogBatchWalkerInterface; use Magento\Framework\Mview\View\ChangelogTableNotExistsException; use Magento\Framework\Mview\View\SubscriptionFactory; use Exception; @@ -66,9 +66,9 @@ class View extends DataObject implements ViewInterface private $changelogBatchSize; /** - * @var ChangeLogBatchIteratorInterface + * @var ChangeLogBatchWalkerFactory */ - private $iterator; + private $changeLogBatchWalkerFactory; /** * @param ConfigInterface $config @@ -78,7 +78,7 @@ class View extends DataObject implements ViewInterface * @param SubscriptionFactory $subscriptionFactory * @param array $data * @param array $changelogBatchSize - * @param ChangeLogBatchIteratorInterface|null $changeLogBatchIterator + * @param ChangeLogBatchWalkerFactory $changeLogBatchWalkerFactory */ public function __construct( ConfigInterface $config, @@ -88,7 +88,7 @@ public function __construct( SubscriptionFactory $subscriptionFactory, array $data = [], array $changelogBatchSize = [], - ChangeLogBatchIteratorInterface $changeLogBatchIterator = null + ChangeLogBatchWalkerFactory $changeLogBatchWalkerFactory = null ) { $this->config = $config; $this->actionFactory = $actionFactory; @@ -97,7 +97,8 @@ public function __construct( $this->subscriptionFactory = $subscriptionFactory; $this->changelogBatchSize = $changelogBatchSize; parent::__construct($data); - $this->iterator = $changeLogBatchIterator; + $this->changeLogBatchWalkerFactory = $changeLogBatchWalkerFactory ?: + ObjectManager::getInstance()->get(ChangeLogBatchWalkerFactory::class); } /** @@ -303,8 +304,8 @@ private function executeAction(ActionInterface $action, int $lastVersionId, int $vsFrom = $lastVersionId; while ($vsFrom < $currentVersionId) { - $iterator = $this->getIterator(); - $ids = $iterator->walk($this->getChangelog(), $vsFrom, $currentVersionId, $batchSize); + $walker = $this->getWalker(); + $ids = $walker->walk($this->getChangelog(), $vsFrom, $currentVersionId, $batchSize); if (empty($ids)) { break; @@ -315,34 +316,16 @@ private function executeAction(ActionInterface $action, int $lastVersionId, int } /** - * Create and validate iterator class for changelog + * Create and validate walker class for changelog * - * @return ChangeLogBatchIteratorInterface|mixed + * @return ChangeLogBatchWalkerInterface|mixed * @throws Exception */ - private function getIterator() + private function getWalker(): ChangeLogBatchWalkerInterface { - if ($this->iterator) { - return $this->iterator; - } - $config = $this->config->getView($this->changelog->getViewId()); - $iteratorClass = $config['iterator']; - - if (!class_exists($iteratorClass)) { - throw new \Exception('Iterator class does not exist for view: ' . $this->changelog->getViewId()); - } - - $iterator = ObjectManager::getInstance()->get($iteratorClass); - - if (!$iterator instanceof ChangeLogBatchIteratorInterface) { - throw new \Exception( - 'Iterator does not implement the right interface for view: ' . - $this->changelog->getViewId() - ); - } - - return $iterator; + $walkerClass = $config['walker']; + return $this->changeLogBatchWalkerFactory->create($walkerClass); } /** diff --git a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/ProcessorFactory.php b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/ProcessorFactory.php new file mode 100644 index 0000000000000..5907cefbffd50 --- /dev/null +++ b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/ProcessorFactory.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Mview\View\AdditionalColumnsProcessor; + +use Magento\Framework\Mview\View\AdditionalColumnProcessorInterface; +use Magento\Framework\ObjectManagerInterface; + +class ProcessorFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * ProcessorFactory constructor. + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Instantiate additional columns processor + * + * @param string $processorClassName + * @return AdditionalColumnProcessorInterface + */ + public function create(string $processorClassName): AdditionalColumnProcessorInterface + { + return $this->objectManager->create($processorClassName); + } +} diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalker.php similarity index 89% rename from lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php rename to lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalker.php index f3ae87b847cb1..7a767e656c3ca 100644 --- a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIterator.php +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalker.php @@ -7,14 +7,13 @@ namespace Magento\Framework\Mview\View; use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Sql\Expression; use Magento\Framework\Phrase; /** - * Interface \Magento\Framework\Mview\View\ChangeLogBatchIterator + * Interface \Magento\Framework\Mview\View\ChangeLogBatchWalkerInterface * */ -class ChangeLogBatchIterator implements ChangeLogBatchIteratorInterface +class ChangeLogBatchWalker implements ChangeLogBatchWalkerInterface { /** * @var ResourceConnection diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalkerFactory.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalkerFactory.php new file mode 100644 index 0000000000000..98d814775f62b --- /dev/null +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalkerFactory.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Mview\View; + +use Magento\Framework\ObjectManagerInterface; + +class ChangeLogBatchWalkerFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * ChangeLogBatchWalkerFactory constructor. + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Instantiate BatchWalker interface + * + * @param string $batchWalkerClassName + * @return ChangeLogBatchWalkerInterface + */ + public function create(string $batchWalkerClassName): ChangeLogBatchWalkerInterface + { + return $this->objectManager->create($batchWalkerClassName); + } +} diff --git a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalkerInterface.php similarity index 84% rename from lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php rename to lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalkerInterface.php index 5e86e0753aec9..d9079c550403c 100644 --- a/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchIteratorInterface.php +++ b/lib/internal/Magento/Framework/Mview/View/ChangeLogBatchWalkerInterface.php @@ -12,10 +12,10 @@ use Magento\Framework\Phrase; /** - * Interface \Magento\Framework\Mview\View\ChangeLogBatchIteratorInterface + * Interface \Magento\Framework\Mview\View\ChangeLogBatchWalkerInterface * */ -interface ChangeLogBatchIteratorInterface +interface ChangeLogBatchWalkerInterface { /** * Walk through batches diff --git a/lib/internal/Magento/Framework/Mview/View/Changelog.php b/lib/internal/Magento/Framework/Mview/View/Changelog.php index 94ce4c19874ce..d26d816e34fea 100644 --- a/lib/internal/Magento/Framework/Mview/View/Changelog.php +++ b/lib/internal/Magento/Framework/Mview/View/Changelog.php @@ -11,6 +11,7 @@ use Magento\Framework\DB\Sql\Expression; use Magento\Framework\Exception\RuntimeException; use Magento\Framework\Mview\Config; +use Magento\Framework\Mview\View\AdditionalColumnsProcessor\ProcessorFactory; use Magento\Framework\Phrase; /** @@ -57,19 +58,27 @@ class Changelog implements ChangelogInterface */ private $mviewConfig; + /** + * @var ProcessorFactory + */ + private $additionalColumnsProcessorFactory; + /** * @param \Magento\Framework\App\ResourceConnection $resource * @param Config $mviewConfig + * @param ProcessorFactory $additionalColumnsProcessorFactory * @throws ConnectionException */ public function __construct( \Magento\Framework\App\ResourceConnection $resource, - Config $mviewConfig + Config $mviewConfig, + ProcessorFactory $additionalColumnsProcessorFactory ) { $this->connection = $resource->getConnection(); $this->resource = $resource; $this->checkConnection(); $this->mviewConfig = $mviewConfig; + $this->additionalColumnsProcessorFactory = $additionalColumnsProcessorFactory; } /** @@ -116,7 +125,7 @@ public function create() foreach ($this->initAdditionalColumnData() as $columnData) { /** @var AdditionalColumnProcessorInterface $processor */ $processorClass = $columnData['processor']; - $processor = ObjectManager::getInstance()->get($processorClass); + $processor = $this->additionalColumnsProcessorFactory->create($processorClass); $processor->processColumnForCLTable($table, $columnData['cl_name']); } diff --git a/lib/internal/Magento/Framework/Mview/etc/mview.xsd b/lib/internal/Magento/Framework/Mview/etc/mview.xsd index 053d1b2853f66..04754fa499249 100644 --- a/lib/internal/Magento/Framework/Mview/etc/mview.xsd +++ b/lib/internal/Magento/Framework/Mview/etc/mview.xsd @@ -46,7 +46,7 @@ <xs:attribute name="id" type="xs:string" use="required" /> <xs:attribute name="class" type="classType" use="required" /> <xs:attribute name="group" type="xs:string" use="required" /> - <xs:attribute name="iterator" type="classType" default="Magento\Framework\Mview\View\LegacyChangeLogBatchIterator" /> + <xs:attribute name="walker" type="classType" default="Magento\Framework\Mview\View\ChangeLogBatchWalker" /> </xs:complexType> <xs:simpleType name="classType"> From 34039643885be75dd1c47d8bad0f0c153a7bf247 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Wed, 4 Nov 2020 17:25:05 +0200 Subject: [PATCH 047/346] Make --- .../Magento/Framework/Mview/View/ChangelogInterface.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php b/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php index 79f998cbe02b6..b00c1ca3a2e33 100644 --- a/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php +++ b/lib/internal/Magento/Framework/Mview/View/ChangelogInterface.php @@ -11,11 +11,6 @@ */ interface ChangelogInterface { - const ATTRIBUTE_SCOPE_SUPPORT = 'attribute_scope'; - const STORE_SCOPE_SUPPORT = 'store_scope'; - const ATTRIBUTE_COLUMN = 'attribute_id'; - const STORE_COLUMN = 'store_id'; - /** * Create changelog table * From 79a82bb212b5b8e274b75d52c815844dbc12b417 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Thu, 5 Nov 2020 16:02:13 -0600 Subject: [PATCH 048/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml index d54b9fada0f4b..3dd87d94d0148 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleCouponData.xml @@ -13,8 +13,4 @@ <data key="is_primary">1</data> <data key="times_used">0</data> </entity> - <entity name="SalesRuleCouponUsageConsumer"> - <data key="consumerName">sales.rule.update.coupon.usage</data> - <data key="messageLimit">100</data> - </entity> </entities> From 895f88bdb193ab3aff733764527e6614a3240f93 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Thu, 5 Nov 2020 17:11:36 -0600 Subject: [PATCH 049/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- ...inCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index 8c64918696f1f..f4814274306c2 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -20,11 +20,8 @@ </annotations> <before> - <!-- Start Coupon Usage Consumer --> - <actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue"> - <argument name="consumerName" value="sales.rule.update.coupon.usage"/> - <argument name="maxMessages" value="1000"/> - </actionGroup> + <!-- Start the consumer --> + <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue"/> <!-- Enable Zero Subtotal Checkout --> <magentoCLI command="config:set {{EnableZeroSubtotalCheckoutConfigData.path}} {{EnableZeroSubtotalCheckoutConfigData.value}}" stepKey="enableZeroSubtotalCheckout"/> From ef7d78ff7b4cda909c0fe7d8e9c35a2b609a2f60 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Fri, 6 Nov 2020 08:41:00 -0600 Subject: [PATCH 050/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index f4814274306c2..4ba5d7f53c03f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -51,6 +51,9 @@ <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> + <!-- Start the consumer --> + <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue1"/> + <!--Create new customer order--> <actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="navigateToNewOrderWithExistingCustomer"> <argument name="customer" value="$$simpleCustomer$$"/> From 937f9e5b767fb9beac965b22c22c8866d9595d95 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Fri, 6 Nov 2020 17:11:47 +0200 Subject: [PATCH 051/346] fix mftf, static --- .../Adminhtml/Order/CreditmemoLoader.php | 14 +++++++++----- ...CreditmemoViewPageWithWrongCreditmemoIdTest.xml | 3 +-- .../Adminhtml/Order/Creditmemo/ViewTest.php | 8 +------- .../Adminhtml/Order/Invoice/ViewTest.php | 7 ------- .../Controller/Adminhtml/Order/ShipmentLoader.php | 3 +-- 5 files changed, 12 insertions(+), 23 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php index 2451b76a5de1a..c1e79b95af038 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/CreditmemoLoader.php @@ -8,12 +8,12 @@ use Magento\Framework\DataObject; use Magento\Sales\Api\CreditmemoRepositoryInterface; -use \Magento\Sales\Model\Order\CreditmemoFactory; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\CreditmemoFactory; /** - * Class CreditmemoLoader + * Loader for creditmemo * - * @package Magento\Sales\Controller\Adminhtml\Order * @method CreditmemoLoader setCreditmemoId($id) * @method CreditmemoLoader setCreditmemo($creditMemo) * @method CreditmemoLoader setInvoiceId($id) @@ -22,6 +22,7 @@ * @method string getCreditmemo() * @method int getInvoiceId() * @method int getOrderId() + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) */ class CreditmemoLoader extends DataObject { @@ -129,7 +130,8 @@ protected function _getItemData() /** * Check if creditmeno can be created for order - * @param \Magento\Sales\Model\Order $order + * + * @param Order $order * @return bool */ protected function _canCreditmemo($order) @@ -153,7 +155,9 @@ protected function _canCreditmemo($order) } /** - * @param \Magento\Sales\Model\Order $order + * Inits invoice + * + * @param Order $order * @return $this|bool */ protected function _initInvoice($order) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml index 696a9f0db2eb0..cf7f61aa12a20 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml @@ -33,7 +33,6 @@ <seeInCurrentUrl url="{{AdminCreditMemosGridPage.url}}" stepKey="redirectToCreditMemosGridPage"/> - <see selector="{{AdminMessagesSection.error}}" userInput='This creditmemo no longer exists.' - stepKey="seeErrorMessage"/> + <actionGroup ref="AssertAdminPageIs404ActionGroup" stepKey="see404PageOnAdmin"/> </test> </tests> diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php index 6e04f4caadc8f..b7249e2af295c 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/ViewTest.php @@ -143,9 +143,6 @@ class ViewTest extends TestCase */ protected function setUp(): void { - $titleMock = $this->getMockBuilder(\Magento\Framework\App\Action\Title::class) - ->disableOriginalConstructor() - ->getMock(); $this->invoiceMock = $this->getMockBuilder(Invoice::class) ->disableOriginalConstructor() ->getMock(); @@ -238,9 +235,6 @@ protected function setUp(): void $this->contextMock->expects($this->any()) ->method('getObjectManager') ->willReturn($this->objectManagerMock); - $this->contextMock->expects($this->any()) - ->method('getTitle') - ->willReturn($titleMock); $this->contextMock->expects($this->any()) ->method('getMessageManager') ->willReturn($this->messageManagerMock); @@ -272,7 +266,7 @@ public function testExecuteNoCreditMemo() $this->loaderMock->expects($this->once()) ->method('load') ->willReturn(false); - + $this->prepareRedirect(); $this->setPath('sales/creditmemo'); $this->assertInstanceOf( diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php index a29ab201e0bd9..d9003b7b4f061 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php @@ -127,10 +127,6 @@ protected function setUp(): void ->disableOriginalConstructor() ->setMethods([]) ->getMock(); - $this->titleMock = $this->getMockBuilder(\Magento\Framework\App\Action\Title::class) - ->disableOriginalConstructor() - ->setMethods([]) - ->getMock(); $this->viewMock = $this->getMockBuilder(\Magento\Framework\App\View::class) ->disableOriginalConstructor() ->setMethods([]) @@ -176,9 +172,6 @@ protected function setUp(): void $contextMock->expects($this->any()) ->method('getResponse') ->willReturn($this->responseMock); - $contextMock->expects($this->any()) - ->method('getTitle') - ->willReturn($this->titleMock); $contextMock->expects($this->any()) ->method('getView') ->willReturn($this->viewMock); diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php index 4f44bfb6458b1..5f0a2fb24c96f 100644 --- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php +++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php @@ -18,9 +18,8 @@ use Magento\Sales\Api\Data\ShipmentItemCreationInterface; /** - * Class ShipmentLoader + * Loader for shipment * - * @package Magento\Shipping\Controller\Adminhtml\Order * @method ShipmentLoader setOrderId($id) * @method ShipmentLoader setShipmentId($id) * @method ShipmentLoader setShipment($shipment) From 6bb81585f10eb347cd4f35c9a286eab0a2d82d39 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Fri, 6 Nov 2020 18:37:18 +0200 Subject: [PATCH 052/346] AddOutOfStockProductToCompareListTest refactored --- ...tHoverProductOnCategoryPageActionGroup.xml | 19 +++ .../AddOutOfStockProductToCompareListTest.xml | 120 ++++++++---------- 2 files changed, 72 insertions(+), 67 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml new file mode 100644 index 0000000000000..661d40fd4f13a --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontHoverProductOnCategoryPageActionGroup"> + <annotations> + <description>Hover product on the Category page</description> + </annotations> + + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverOverProduct"/> + + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml index 92be79fdfe720..b2fbf2ae3810a 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml @@ -20,7 +20,6 @@ <group value="Catalog"/> </annotations> <before> - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockDisable.path}} {{CatalogInventoryOptionsShowOutOfStockDisable.value}}" stepKey="setConfigShowOutOfStockFalse"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> @@ -30,81 +29,68 @@ <requiredEntity createDataKey="category"/> </createData> </before> + <after> - <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockDisable.path}} {{CatalogInventoryOptionsShowOutOfStockDisable.value}}" stepKey="setConfigShowOutOfStockFalse"/> + <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockDisable.path}} {{CatalogInventoryOptionsShowOutOfStockDisable.value}}" stepKey="setConfigShowOutOfStockFalse"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> - <deleteData createDataKey="product" stepKey="deleteProduct"/> - <deleteData createDataKey="category" stepKey="deleteCategory"/> - <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> </after> - <!--Open product page--> - <comment userInput="Open product page" stepKey="openProdPage"/> - <amOnPage url="{{StorefrontProductPage.url($$product.custom_attributes[url_key]$$)}}" stepKey="goToSimpleProductPage"/> - <waitForPageLoad stepKey="waitForSimpleProductPage"/> - <!--'Add to compare' link is not available--> - <comment userInput="'Add to compare' link is not available" stepKey="addToCompareLinkAvailability"/> + + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductStorefront"> + <argument name="productUrl" value="$$product.custom_attributes[url_key]$$"/> + </actionGroup> + <dontSeeElement selector="{{StorefrontProductInfoMainSection.productAddToCompare}}" stepKey="dontSeeAddToCompareLink"/> - <!--Turn on 'out on stock' config--> - <comment userInput="Turn on 'out of stock' config" stepKey="onOutOfStockConfig"/> + <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockEnable.path}} {{CatalogInventoryOptionsShowOutOfStockEnable.value}}" stepKey="setConfigShowOutOfStockTrue"/> - <!--Clear cache and reindex--> - <comment userInput="Clear cache and reindex" stepKey="cleanCache"/> + <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> -</actionGroup> + <argument name="indices" value=""/> + </actionGroup> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> - <argument name="tags" value=""/> -</actionGroup> - <!--Open product page--> - <comment userInput="Open product page" stepKey="openProductPage"/> - <amOnPage url="{{StorefrontProductPage.url($$product.custom_attributes[url_key]$$)}}" stepKey="goToSimpleProductPage2"/> - <waitForPageLoad stepKey="waitForSimpleProductPage2"/> - <!--Click on 'Add to Compare' link--> - <waitForElementVisible selector="{{StorefrontProductInfoMainSection.productAddToCompare}}" stepKey="seeAddToCompareLink"/> - <comment userInput="Click on 'Add to Compare' link" stepKey="clickOnAddToCompareLink"/> - <click selector="{{StorefrontProductInfoMainSection.productAddToCompare}}" stepKey="clickOnAddToCompare"/> - <waitForPageLoad stepKey="waitForProdAddToCmpList"/> - <!--Assert success message--> - <comment userInput="Assert success message" stepKey="assertSuccessMsg"/> - <grabTextFrom selector="{{StorefrontMessagesSection.success}}" stepKey="grabTextFromSuccessMessage"/> - <assertEquals stepKey="assertSuccessMessage"> - <actualResult type="const">($grabTextFromSuccessMessage)</actualResult> - <expectedResult type="string">You added product $$product.name$$ to the comparison list.</expectedResult> - </assertEquals> - <!--See product in the comparison list--> - <comment userInput="See product in the comparison list" stepKey="seeProductInComparisonList"/> - <amOnPage url="{{StorefrontProductComparePage.url}}" stepKey="navigateToComparePage"/> - <waitForPageLoad stepKey="waitForStorefrontProductComparePageLoad"/> - <seeElement selector="{{StorefrontProductCompareMainSection.ProductLinkByName($product.name$)}}" stepKey="seeProductInCompareList"/> - <!--Go to Category page and delete product from comparison list--> - <comment userInput="Go to Category page and delete product from comparison list" stepKey="deleteProdFromCmpList"/> - <amOnPage url="{{StorefrontCategoryPage.url($$category.name$$)}}" stepKey="onCategoryPage"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> - <click selector="{{StorefrontComparisonSidebarSection.ClearAll}}" stepKey="clickClearAll"/> - <waitForPageLoad time="30" stepKey="waitForConfirmPageLoad"/> - <click selector="{{AdminDeleteRoleSection.confirm}}" stepKey="confirmProdDelate"/> - <waitForPageLoad time="30" stepKey="waitForConfirmLoad"/> - <!--Add product to compare list from Category page--> - <comment userInput="Add product to compare list fom Category page" stepKey="addToCmpFromCategPage"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverOverProduct"/> - <click selector="{{StorefrontProductInfoMainSection.productAddToCompare}}" stepKey="clickAddToCompare"/> - <waitForPageLoad stepKey="waitProdAddingToCmpList"/> - <!--Assert success message--> - <comment userInput="Assert success message" stepKey="assertSuccessMsg2"/> - <grabTextFrom selector="{{StorefrontMessagesSection.success}}" stepKey="grabTextFromSuccessMessage2"/> - <assertEquals stepKey="assertSuccessMessage2"> - <actualResult type="const">($grabTextFromSuccessMessage)</actualResult> - <expectedResult type="string">You added product $$product.name$$ to the comparison list.</expectedResult> - </assertEquals> - <!--Check that product displays on add to compare widget--> - <comment userInput="Check that product displays on add to compare widget" stepKey="checkProdNameOnWidget"/> + <argument name="tags" value=""/> + </actionGroup> + + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductStorefront1"> + <argument name="productUrl" value="$$product.custom_attributes[url_key]$$"/> + </actionGroup> + + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="addProductToCompare1"> + <argument name="productVar" value="$$product$$"/> + </actionGroup> + + <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="openCategoryPage"> + <argument name="categoryName" value="$$category.name$$"/> + </actionGroup> + + <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="compareOpenComparePage"/> + + <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInComparisonList"> + <argument name="productVar" value="$$product$$"/> + </actionGroup> + + <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="openCategoryPage1"> + <argument name="categoryName" value="$$category.name$$"/> + </actionGroup> + + <actionGroup ref="StorefrontClearCompareActionGroup" stepKey="clearList"/> + + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> + + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="addProductToCompare2"> + <argument name="productVar" value="$$product$$"/> + </actionGroup> + <seeElement selector="{{StorefrontComparisonSidebarSection.ProductTitleByName($$product.name$$)}}" stepKey="seeProdNameOnCmpWidget"/> - <!--See product in the compare page--> - <comment userInput="See product in the compare page" stepKey="seeProductInComparePage"/> - <amOnPage url="{{StorefrontProductComparePage.url}}" stepKey="navigateToComparePage2"/> - <waitForPageLoad stepKey="waitForStorefrontProductComparePageLoad2"/> - <seeElement selector="{{StorefrontProductCompareMainSection.ProductLinkByName($product.name$)}}" stepKey="seeProductInCompareList2"/> + + <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="compareOpenComparePage1"/> + + <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInComparisonList1"> + <argument name="productVar" value="$$product$$"/> + </actionGroup> + </test> </tests> From 2ffaa301fa910189c3a5bb9c073b7ee0794f9cb6 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Fri, 6 Nov 2020 11:21:16 -0600 Subject: [PATCH 053/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index 4ba5d7f53c03f..691f18058b0df 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -72,6 +72,9 @@ <actionGroup ref="VerifyCreatedOrderInformationActionGroup" stepKey="verifyCreatedOrderInformation"/> <grabTextFrom selector="|Order # (\d+)|" stepKey="orderId"/> + <!-- Start the consumer --> + <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue2"/> + <!-- Cancel the Order --> <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOrder"/> From e39d6e93b01a7b88dc7f13c4968f21fb6a714daf Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Fri, 6 Nov 2020 11:44:03 -0600 Subject: [PATCH 054/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- ...nCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index 691f18058b0df..aad1c4d831a11 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -68,13 +68,15 @@ <actionGroup ref="AdminSelectFlatRateShippingMethodActionGroup" stepKey="selectFlatRateShippingMethod"/> <actionGroup ref="AdminOrderClickSubmitOrderActionGroup" stepKey="submitOrder" /> + <!-- Start the consumer --> + <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue2"/> + <reloadPage stepKey="refreshPage"/> + <!--Verify order information--> <actionGroup ref="VerifyCreatedOrderInformationActionGroup" stepKey="verifyCreatedOrderInformation"/> + <reloadPage stepKey="refreshPage"/> <grabTextFrom selector="|Order # (\d+)|" stepKey="orderId"/> - <!-- Start the consumer --> - <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue2"/> - <!-- Cancel the Order --> <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOrder"/> From 01ee9ea91b73ffe83452a4fe4fc2011163a3afdb Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Fri, 6 Nov 2020 15:25:41 -0600 Subject: [PATCH 055/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- ...AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index aad1c4d831a11..b4cd75d9cc498 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -70,11 +70,11 @@ <!-- Start the consumer --> <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue2"/> - <reloadPage stepKey="refreshPage"/> + <reloadPage stepKey="refreshPage1"/> <!--Verify order information--> <actionGroup ref="VerifyCreatedOrderInformationActionGroup" stepKey="verifyCreatedOrderInformation"/> - <reloadPage stepKey="refreshPage"/> + <reloadPage stepKey="refreshPage2"/> <grabTextFrom selector="|Order # (\d+)|" stepKey="orderId"/> <!-- Cancel the Order --> From 9bea792f606ab0b87e8bfed0ba1652e78ddf9a2a Mon Sep 17 00:00:00 2001 From: Oleh Usik <o.usik@atwix.com> Date: Sat, 7 Nov 2020 17:55:10 +0200 Subject: [PATCH 056/346] add Assert link action group --- .../ActionGroup/AssertLinkActionGroup.xml | 22 +++++++ .../Test/Mftf/Test/AdminPrivacyPolicyTest.xml | 59 +++++++++++++------ 2 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertLinkActionGroup.xml diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertLinkActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertLinkActionGroup.xml new file mode 100644 index 0000000000000..6fa63d14b9612 --- /dev/null +++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AssertLinkActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertLinkActionGroup"> + <annotations> + <description>Assert text and url of the links.</description> + </annotations> + <arguments> + <argument name="text" type="string"/> + <argument name="url" type="string"/> + </arguments> + + <seeLink userInput="{{text}}" url="{{url}}" stepKey="assertLinks"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminPrivacyPolicyTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminPrivacyPolicyTest.xml index b0fbdb8b5b596..8b0bf1dc963ff 100644 --- a/app/code/Magento/Backend/Test/Mftf/Test/AdminPrivacyPolicyTest.xml +++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminPrivacyPolicyTest.xml @@ -23,70 +23,91 @@ <!-- Logging in Magento admin and checking for Privacy policy footer in dashboard --> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <closeAdminNotification stepKey="closeAdminNotification"/> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkDashboard"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkDashboard"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in salesOrderPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToSalesOrder"> <argument name="menuUiId" value="magento-sales-sales"/> <argument name="submenuUiId" value="magento-sales-sales-order"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkSalesOrder"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkSalesOrder"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in catalogProductsPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToCatalogProducts"> <argument name="menuUiId" value="magento-catalog-catalog"/> <argument name="submenuUiId" value="magento-catalog-catalog-products"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkCatalogProducts"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkCatalogProducts"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in customersAllCustomersPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToCustomersAllCustomers"> <argument name="menuUiId" value="magento-customer-customer"/> <argument name="submenuUiId" value="magento-customer-customer-manage"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkCustomersAllCustomers"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkCustomersAllCustomers"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in marketingCatalogPriceRulePage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToMarketingCatalogPriceRule"> <argument name="menuUiId" value="magento-backend-marketing"/> <argument name="submenuUiId" value="magento-catalogrule-promo-catalog"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkMarketingCatalogPriceRule"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkMarketingCatalogPriceRule"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in contentBlocksPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToContentBlocks"> <argument name="menuUiId" value="magento-backend-content"/> <argument name="submenuUiId" value="magento-cms-cms-block"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkContentBlocks"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkContentBlocks"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in reportSearcbTermsPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToReportsSearchTerms"> <argument name="menuUiId" value="magento-reports-report"/> <argument name="submenuUiId" value="magento-search-report-search-term"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkReportsSearchTerms"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkReportsSearchTerms"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in storesAllStoresPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToStoresAllStores"> <argument name="menuUiId" value="magento-backend-stores"/> <argument name="submenuUiId" value="magento-backend-system-store"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkStoresAllStores"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkStoresAllStores"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in systemImportPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToSystemImport"> <argument name="menuUiId" value="magento-backend-system"/> <argument name="submenuUiId" value="magento-importexport-system-convert-import"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkSystemImport"/> - + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkSystemImport"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> <!-- Checking for Privacy policy footer in findPartnersAndExtensionsPage --> <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToFindPartnersAndExtensions"> <argument name="menuUiId" value="magento-marketplace-partners"/> <argument name="submenuUiId" value="magento-marketplace-partners"/> </actionGroup> - <seeLink userInput="Privacy Policy" url="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf" stepKey="seePrivacyPolicyLinkFindPartnersAndExtensions"/> + <actionGroup ref="AssertLinkActionGroup" stepKey="seePrivacyPolicyLinkFindPartnersAndExtensions"> + <argument name="text" value="Privacy Policy"/> + <argument name="url" value="https://magento.com/sites/default/files/REVISED-MAGENTO-PRIVACY-POLICY.pdf"/> + </actionGroup> </test> </tests> From 83e45ae5fd20f8aa167c970bf4b25eb0cde9df98 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Mon, 9 Nov 2020 13:52:49 -0600 Subject: [PATCH 057/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- ...nCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index b4cd75d9cc498..71ca3e8a79060 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -20,9 +20,6 @@ </annotations> <before> - <!-- Start the consumer --> - <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue"/> - <!-- Enable Zero Subtotal Checkout --> <magentoCLI command="config:set {{EnableZeroSubtotalCheckoutConfigData.path}} {{EnableZeroSubtotalCheckoutConfigData.value}}" stepKey="enableZeroSubtotalCheckout"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> @@ -50,10 +47,6 @@ <deleteData createDataKey="simpleProduct" stepKey="deleteSimpleProduct"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> - - <!-- Start the consumer --> - <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue1"/> - <!--Create new customer order--> <actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="navigateToNewOrderWithExistingCustomer"> <argument name="customer" value="$$simpleCustomer$$"/> @@ -70,7 +63,6 @@ <!-- Start the consumer --> <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue2"/> - <reloadPage stepKey="refreshPage1"/> <!--Verify order information--> <actionGroup ref="VerifyCreatedOrderInformationActionGroup" stepKey="verifyCreatedOrderInformation"/> From 1143af933f5cf6ab4a2c49d583fb3cd0a1c46c02 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Mon, 9 Nov 2020 13:54:07 -0600 Subject: [PATCH 058/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index 71ca3e8a79060..dcb27595cf042 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -69,6 +69,8 @@ <reloadPage stepKey="refreshPage2"/> <grabTextFrom selector="|Order # (\d+)|" stepKey="orderId"/> + <reloadPage stepKey="refreshPage1"/> + <!-- Cancel the Order --> <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOrder"/> From a8c96887994a53e0503f49a64a689fcd76d69c7b Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Mon, 9 Nov 2020 17:08:04 -0600 Subject: [PATCH 059/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- ...elTheCreatedOrderWithZeroSubtotalCheckoutTest.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml index dcb27595cf042..21ced2e2df278 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCancelTheCreatedOrderWithZeroSubtotalCheckoutTest.xml @@ -35,7 +35,7 @@ <field key="price">10.00</field> </createData> - <!-- Create a slaes rule with fixed discount --> + <!-- Create a sales rule with fixed discount --> <createData entity="SalesRuleNoCouponWithFixedDiscount" stepKey="createSalesRule"/> </before> <after> @@ -62,14 +62,18 @@ <actionGroup ref="AdminOrderClickSubmitOrderActionGroup" stepKey="submitOrder" /> <!-- Start the consumer --> - <magentoCLI command="queue:consumers:start sales.rule.update.coupon.usage --max-messages=100" stepKey="startMessageQueue2"/> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue"> + <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> + <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> + </actionGroup> <!--Verify order information--> <actionGroup ref="VerifyCreatedOrderInformationActionGroup" stepKey="verifyCreatedOrderInformation"/> - <reloadPage stepKey="refreshPage2"/> + <reloadPage stepKey="refreshPage"/> <grabTextFrom selector="|Order # (\d+)|" stepKey="orderId"/> - <reloadPage stepKey="refreshPage1"/> + <!-- Refresh the page --> + <reloadPage stepKey="refreshPageAgain"/> <!-- Cancel the Order --> <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOrder"/> From 396ab4de86c1fcd9952c691a29d5a01acd208e79 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Mon, 9 Nov 2020 17:08:22 -0600 Subject: [PATCH 060/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Test/Mftf/Data/SalesRuleQueueData.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml new file mode 100644 index 0000000000000..1e3cf57e8777b --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SalesRuleConsumerData"> + <data key="consumerName">sales.rule.update.coupon.usage</data> + <data key="messageLimit">100</data> + </entity> +</entities> From b77d2296a68b16fd8a102b1216de5803293486cd Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@adobe.com> Date: Mon, 9 Nov 2020 17:11:11 -0600 Subject: [PATCH 061/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index 74542be376c45..84b32beceb06e 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -58,11 +58,15 @@ <see selector="{{AdminCartPriceRulesFormSection.successMessage}}" userInput="Message is added to queue, wait to get your coupons soon" stepKey="seeSuccessMessage"/> - <!-- Start message queue for export consumer --> + <!-- Start message queue for export consumer and coupon processing --> <actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue"> <argument name="consumerName" value="{{AdminCodeGeneratorMessageConsumerData.consumerName}}"/> <argument name="maxMessages" value="{{AdminCodeGeneratorMessageConsumerData.messageLimit}}"/> </actionGroup> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startSalesRuleMessageQueue"> + <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> + <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> + </actionGroup> <actionGroup ref="ReloadPageActionGroup" stepKey="refreshPage"/> <comment userInput="Replacing reload action and preserve Backward Compatibility" stepKey="waitFormToReload1"/> <conditionalClick selector="{{AdminCartPriceRulesFormSection.manageCouponCodesHeader}}" From a4f66bd38ebf2d889dbc90ca517d2c4ef1f8869f Mon Sep 17 00:00:00 2001 From: Zach Nanninga <zach@mediotype.com> Date: Wed, 11 Nov 2020 11:25:51 -0600 Subject: [PATCH 062/346] ISSUE-30880 - Add CSP entry to allow google analytics ajax --- app/code/Magento/GoogleAdwords/etc/csp_whitelist.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/GoogleAdwords/etc/csp_whitelist.xml b/app/code/Magento/GoogleAdwords/etc/csp_whitelist.xml index d700b0e9e7668..6d8d42a5d3f8f 100644 --- a/app/code/Magento/GoogleAdwords/etc/csp_whitelist.xml +++ b/app/code/Magento/GoogleAdwords/etc/csp_whitelist.xml @@ -14,6 +14,11 @@ <value id="google_analytics" type="host">www.google-analytics.com</value> </values> </policy> + <policy id="connect-src"> + <values> + <value id="google_analytics" type="host">www.google-analytics.com</value> + </values> + </policy> <policy id="img-src"> <values> <value id="google_ad_services" type="host">www.googleadservices.com</value> From 32ae2ffa2441992e13b45e5606b2a0c8fb5d76f0 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Mon, 16 Nov 2020 13:48:07 +0200 Subject: [PATCH 063/346] fix static --- .../Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php index d9003b7b4f061..3429b3df85b8a 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/ViewTest.php @@ -31,6 +31,7 @@ /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD.TooManyFields) */ class ViewTest extends TestCase { From e3276fcf458ccc8d35248d2d83a68c73908afd63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vinicius=20Bordinh=C3=A3o?= <vinicius.bordinhao@blueacornici.com> Date: Mon, 16 Nov 2020 16:07:45 -0300 Subject: [PATCH 064/346] ISSUE-29690: Fixing issue when the images's order was using ID instead of position. --- .../Block/Plugin/Product/Media/Gallery.php | 16 +++++++++++++++- .../Block/Plugin/Product/Media/GalleryTest.php | 10 +++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php b/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php index 1df68482eb6b8..21bfb3b873a7b 100644 --- a/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php +++ b/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php @@ -59,7 +59,7 @@ public function afterGetOptionsMediaGalleryDataJson( private function getProductGallery($product) { $result = []; - $images = $product->getMediaGalleryImages(); + $images = $this->getImagesOrderedByPosition($product); foreach ($images as $image) { $result[] = [ 'mediaType' => $image->getMediaType(), @@ -69,4 +69,18 @@ private function getProductGallery($product) } return $result; } + + /** + * @param Product $product + * @return array + */ + private function getImagesOrderedByPosition($product) + { + $imagesCollection = $product->getMediaGalleryImages(); + $images = $imagesCollection->getItems(); + usort($images, function ($el1, $el2) { + return $el1['position'] <=> $el2['position']; + }); + return $images; + } } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php index 16f9697d8ceda..367b639176665 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php @@ -11,6 +11,7 @@ use Magento\ConfigurableProduct\Block\Plugin\Product\Media\Gallery; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; use Magento\Framework\DataObject; +use Magento\Framework\Data\Collection as DataCollection; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use PHPUnit\Framework\MockObject\MockObject; @@ -41,13 +42,20 @@ public function testAfterGetOptions() ['media_type' => 'type', 'video_url' => 'url', 'file' => 'image.jpg'] ); + $dataCollection = $this->getMockBuilder(DataCollection::class) + ->disableOriginalConstructor() + ->onlyMethods(['getItems']) + ->getMock(); + + $galleryMock->expects(($this->any()))->method('getProduct')->willReturn($productMock); $productMock->expects($this->once())->method('getTypeId')->willReturn('configurable'); $productMock->expects($this->once())->method('getTypeInstance')->willReturn($configurableTypeMock); $configurableTypeMock->expects($this->once())->method('getUsedProducts')->with($productMock) ->willReturn([$variationProductMock]); $variationProductMock->expects($this->once())->method('getId')->willReturn($variationProductId); - $variationProductMock->expects($this->once())->method('getMediaGalleryImages')->willReturn([$image]); + $variationProductMock->expects($this->once())->method('getMediaGalleryImages')->willReturn($dataCollection); + $dataCollection->expects($this->once())->method('getItems')->willReturn([$image]); $variationProductMock->expects($this->once())->method('getImage')->willReturn('image.jpg'); $jsonMock->expects($this->once())->method('serialize')->with($expectedGalleryJson) ->willReturn(json_encode($expectedGalleryJson)); From b65b86c6497686fed0316a1af45ede3cdc567f57 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Mon, 16 Nov 2020 17:27:38 -0600 Subject: [PATCH 065/346] MC-38900: Mutation setGuestEmailOnCart doesn't update quote address --- app/code/Magento/Quote/Model/Quote/Address.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index aee86eb1f8935..5ecae97834eb0 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -139,7 +139,7 @@ class Address extends AbstractAddress implements const ADDRESS_TYPE_BILLING = 'billing'; const ADDRESS_TYPE_SHIPPING = 'shipping'; - + private const CACHED_ITEMS_ALL = 'cached_items_all'; /** @@ -1652,12 +1652,7 @@ public function setCustomerId($customerId) */ public function getEmail() { - $email = $this->getData(self::KEY_EMAIL); - if (!$email && $this->getQuote()) { - $email = $this->getQuote()->getCustomerEmail(); - $this->setEmail($email); - } - return $email; + return $this->getData(self::KEY_EMAIL); } /** From 88272b7f4750a17d2527dc4a77a4c36334154129 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 17 Nov 2020 09:38:42 -0600 Subject: [PATCH 066/346] MC-38900: Mutation setGuestEmailOnCart doesn't update quote address --- app/code/Magento/Quote/Model/Quote/Address.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 5ecae97834eb0..9da6c9b0b61a1 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -1652,7 +1652,13 @@ public function setCustomerId($customerId) */ public function getEmail() { - return $this->getData(self::KEY_EMAIL); + $email = $this->getData(self::KEY_EMAIL); + $q = $this->getQuote(); + if (!$email && $this->getQuote() && $this->getQuote()->dataHasChangedFor('email')) { + $email = $this->getQuote()->getCustomerEmail(); + $this->setEmail($email); + } + return $email; } /** From cb5b1b86ed5aa6918639868f4622de3d284e4079 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 17 Nov 2020 13:35:19 -0600 Subject: [PATCH 067/346] MC-38900: Mutation setGuestEmailOnCart doesn't update quote address --- app/code/Magento/Quote/Model/Quote/Address.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 9da6c9b0b61a1..0edf603d131f8 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -1653,8 +1653,7 @@ public function setCustomerId($customerId) public function getEmail() { $email = $this->getData(self::KEY_EMAIL); - $q = $this->getQuote(); - if (!$email && $this->getQuote() && $this->getQuote()->dataHasChangedFor('email')) { + if (!$email && $this->getQuote() && $this->getQuote()->dataHasChangedFor('customer_email')) { $email = $this->getQuote()->getCustomerEmail(); $this->setEmail($email); } From 17b76e616ef353802acbb7b0b17101879e21b4f7 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 17 Nov 2020 13:42:25 -0600 Subject: [PATCH 068/346] MC-38900: Mutation setGuestEmailOnCart doesn't update quote address --- app/code/Magento/Quote/Model/Quote/Address.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index 0edf603d131f8..f918d480dd4e0 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -1653,7 +1653,7 @@ public function setCustomerId($customerId) public function getEmail() { $email = $this->getData(self::KEY_EMAIL); - if (!$email && $this->getQuote() && $this->getQuote()->dataHasChangedFor('customer_email')) { + if ($this->getQuote() && (!$email || $this->getQuote()->dataHasChangedFor('customer_email'))) { $email = $this->getQuote()->getCustomerEmail(); $this->setEmail($email); } From 20ce0894bd18e9b1375831ad9f8e2387f7e1f319 Mon Sep 17 00:00:00 2001 From: Victor Rad <vrad@magento.com> Date: Tue, 17 Nov 2020 14:26:06 -0600 Subject: [PATCH 069/346] MC-39024: Rest api PUT /V1/products/:sku/links calls does not update indexer by cron:run --- app/code/Magento/Catalog/etc/mview.xml | 2 + .../Magento/CatalogInventory/etc/mview.xml | 1 + app/code/Magento/CatalogRule/etc/mview.xml | 1 + .../Api/ProductLinkRepositoryTest.php | 122 +++++++++++++++++- 4 files changed, 124 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/etc/mview.xml b/app/code/Magento/Catalog/etc/mview.xml index 7ae38a7f2d0e1..2c9d7d448afd2 100644 --- a/app/code/Magento/Catalog/etc/mview.xml +++ b/app/code/Magento/Catalog/etc/mview.xml @@ -49,6 +49,7 @@ <table name="catalog_product_entity_decimal" entity_column="entity_id" /> <table name="catalog_product_entity_int" entity_column="entity_id" /> <table name="catalog_product_entity_tier_price" entity_column="entity_id" /> + <table name="catalog_product_link" entity_column="product_id" /> </subscriptions> </view> <view id="catalog_product_attribute" class="Magento\Catalog\Model\Indexer\Product\Eav" group="indexer"> @@ -56,6 +57,7 @@ <table name="catalog_product_entity_decimal" entity_column="entity_id" /> <table name="catalog_product_entity_int" entity_column="entity_id" /> <table name="catalog_product_entity_varchar" entity_column="entity_id" /> + <table name="catalog_product_link" entity_column="product_id" /> </subscriptions> </view> </config> diff --git a/app/code/Magento/CatalogInventory/etc/mview.xml b/app/code/Magento/CatalogInventory/etc/mview.xml index 338f1fe0610a1..9733fa32583f1 100644 --- a/app/code/Magento/CatalogInventory/etc/mview.xml +++ b/app/code/Magento/CatalogInventory/etc/mview.xml @@ -11,6 +11,7 @@ <table name="cataloginventory_stock_item" entity_column="product_id" /> <!--Track product status to trigger stock indexer--> <table name="catalog_product_entity_int" entity_column="entity_id" /> + <table name="catalog_product_link" entity_column="product_id" /> </subscriptions> </view> <view id="catalog_product_price" class="Magento\Catalog\Model\Indexer\Product\Price" group="indexer"> diff --git a/app/code/Magento/CatalogRule/etc/mview.xml b/app/code/Magento/CatalogRule/etc/mview.xml index 9f793d5c8c393..106e0ffabb2b2 100644 --- a/app/code/Magento/CatalogRule/etc/mview.xml +++ b/app/code/Magento/CatalogRule/etc/mview.xml @@ -21,6 +21,7 @@ <table name="catalog_product_entity_tier_price" entity_column="entity_id" /> <table name="catalog_product_entity_varchar" entity_column="entity_id" /> <table name="catalog_category_product" entity_column="product_id" /> + <table name="catalog_product_link" entity_column="product_id" /> </subscriptions> </view> <view id="catalog_product_price" class="Magento\Catalog\Model\Indexer\Product\Price" group="indexer"> diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkRepositoryTest.php index 11e07d081636e..efa7341c36a40 100644 --- a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductLinkRepositoryTest.php @@ -7,28 +7,44 @@ namespace Magento\GroupedProduct\Api; use Magento\TestFramework\Helper\Bootstrap; +use Magento\Indexer\Model\Config; +use Magento\Framework\Indexer\IndexerRegistry; +use Magento\Framework\Webapi\Rest\Request; class ProductLinkRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstract { const SERVICE_NAME = 'catalogProductLinkRepositoryV1'; const SERVICE_VERSION = 'V1'; const RESOURCE_PATH = '/V1/products/'; + const SERVICE_NAME_SEARCH = 'searchV1'; + const RESOURCE_PATH_SEARCH = '/V1/search/'; /** * @var \Magento\Framework\ObjectManagerInterface */ protected $objectManager; + /** + * @var array + */ + private $indexersState; + + /** + * @var mixed + */ + private $indexerRegistry; + protected function setUp(): void { $this->objectManager = Bootstrap::getObjectManager(); + $this->indexerRegistry = $this->objectManager->get(IndexerRegistry::class); } /** * @magentoApiDataFixture Magento/Catalog/_files/product_simple_duplicated.php * @magentoApiDataFixture Magento/GroupedProduct/_files/product_grouped.php */ - public function testSave() + public function testSave(): void { $productSku = 'grouped-product'; $linkType = 'associated'; @@ -46,7 +62,7 @@ public function testSave() $serviceInfo = [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH . $productSku . '/links', - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT, + 'httpMethod' => Request::HTTP_METHOD_PUT, ], 'soap' => [ 'service' => self::SERVICE_NAME, @@ -64,4 +80,106 @@ public function testSave() }); $this->assertEquals($productData, $actual[2]); } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_simple_duplicated.php + * @magentoApiDataFixture Magento/GroupedProduct/_files/product_grouped.php + */ + public function testLinkWithScheduledIndex(): void + { + $this->setIndexScheduled(); + $productSkuGrouped = 'grouped-product'; + $productSimple = 'simple-1'; + $linkType = 'associated'; + $productData = [ + 'sku' => $productSkuGrouped, + 'link_type' => $linkType, + 'linked_product_type' => 'simple', + 'linked_product_sku' => $productSimple, + 'position' => 3, + 'extension_attributes' => [ + 'qty' => (float) 300.0000, + ], + ]; + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $productSkuGrouped . '/links', + 'httpMethod' => Request::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + $this->_webApiCall($serviceInfo, ['entity' => $productData]); + + $searchCriteria = $this->buildSearchCriteria($productSimple); + $serviceInfo = $this->buildSearchServiceInfo($searchCriteria); + $response = $this->_webApiCall($serviceInfo, $searchCriteria); + $this->assertArrayHasKey('search_criteria', $response); + $this->assertArrayHasKey('items', $response); + $this->assertGreaterThan(1, count($response['items'])); + $this->assertGreaterThan(0, $response['items'][0]['id']); + $this->restoreIndexMode(); + } + + /** + * @param string $productSku + * @return array + */ + private function buildSearchCriteria(string $productSku): array + { + return [ + 'searchCriteria' => [ + 'request_name' => 'quick_search_container', + 'filter_groups' => [ + [ + 'filters' => [ + [ + 'field' => 'search_term', + 'value' => $productSku, + ] + ] + ] + ] + ] + ]; + } + + /** + * @param array $searchCriteria + * @return array + */ + private function buildSearchServiceInfo(array $searchCriteria): array + { + return [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH_SEARCH . '?' . http_build_query($searchCriteria), + 'httpMethod' => Request::HTTP_METHOD_GET + ], + 'soap' => [ + 'service' => self::SERVICE_NAME_SEARCH, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME_SEARCH . 'Search' + ] + ]; + } + + private function setIndexScheduled(): void + { + $indexerListIds = $this->objectManager->get(Config::class)->getIndexers(); + foreach ($indexerListIds as $indexerId) { + $indexer = $this->indexerRegistry->get($indexerId['indexer_id']); + $this->indexersState[$indexerId['indexer_id']] = $indexer->isScheduled(); + $indexer->setScheduled(true); + } + } + + private function restoreIndexMode(): void + { + foreach ($this->indexersState as $indexerId => $state) { + $this->indexerRegistry->get($indexerId)->setScheduled($state); + } + } } From 0a27db2a4a75e53d6531130a1f1b601477dc6e2f Mon Sep 17 00:00:00 2001 From: Nikola Lardev <nikolalardev@gmail.com> Date: Wed, 18 Nov 2020 00:37:15 +0200 Subject: [PATCH 070/346] Add regions for Albania,Denmark,Greece,Iceland,Portugal and Sweden --- .../Setup/Patch/Data/AddDataForAlbania.php | 99 ++++++++++++++++ .../Setup/Patch/Data/AddDataForDenmark.php | 92 +++++++++++++++ .../Setup/Patch/Data/AddDataForGreece.php | 101 ++++++++++++++++ .../Setup/Patch/Data/AddDataForIceland.php | 95 +++++++++++++++ .../Setup/Patch/Data/AddDataForPortugal.php | 107 +++++++++++++++++ .../Setup/Patch/Data/AddDataForSweden.php | 108 ++++++++++++++++++ .../Magento/Directory/Model/RegionTest.php | 8 +- 7 files changed, 609 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForAlbania.php create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForDenmark.php create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForIceland.php create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForSweden.php diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForAlbania.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForAlbania.php new file mode 100644 index 0000000000000..14aaffa1857ef --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForAlbania.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Directory\Setup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Directory\Setup\DataInstallerFactory; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add Albania States + */ +class AddDataForAlbania implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * AddDataForAlbania constructor. + * + * @param ModuleDataSetupInterface $moduleDataSetup + * @param DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForAlbania() + ); + + return $this; + } + + /** + * Albania states data. + * + * @return array + */ + private function getDataForAlbania() + { + return [ + ['AL', 'AL-01', 'Berat'], + ['AL', 'AL-09', 'Dibër'], + ['AL', 'AL-02', 'Durrës'], + ['AL', 'AL-03', 'Elbasan'], + ['AL', 'AL-04', 'Fier'], + ['AL', 'AL-05', 'Gjirokastër'], + ['AL', 'AL-06', 'Korçë'], + ['AL', 'AL-07', 'Kukës'], + ['AL', 'AL-08', 'Lezhë'], + ['AL', 'AL-10', 'Shkodër'], + ['AL', 'AL-11', 'Tiranë'], + ['AL', 'AL-12', 'Vlorë'] + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForDenmark.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForDenmark.php new file mode 100644 index 0000000000000..1415227a932e6 --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForDenmark.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Directory\Setup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Directory\Setup\DataInstallerFactory; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add Denmark States + */ +class AddDataForDenmark implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * AddDataForDenmark constructor. + * + * @param ModuleDataSetupInterface $moduleDataSetup + * @param DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForDenmark() + ); + + return $this; + } + + /** + * Denmark states data. + * + * @return array + */ + private function getDataForDenmark() + { + return [ + ['DK', 'DK-84', 'Hovedstaden'], + ['DK', 'DK-82', 'Midtjylland'], + ['DK', 'DK-81', 'Nordjylland'], + ['DK', 'DK-85', 'Sjælland'], + ['DK', 'DK-83', 'Syddanmark'], + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php new file mode 100644 index 0000000000000..a756035f1af4e --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php @@ -0,0 +1,101 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reGRrved. + * GRe COPYING.txt for licenGR details. + */ +declare(strict_types=1); + +namespace Magento\Directory\GRtup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Directory\Setup\DataInstallerFactory; +use Magento\Framework\Setup\ModuleDataGRtupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add Greece States + */ +class AddDataForGreece implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataGRtup; + + /** + * @var DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * AddDataForGreece constructor. + * + * @param ModuleDataSetupInterface $moduleDataSetup + * @param DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForGreece() + ); + + return $this; + } + + /** + * Greece states data. + * + * @return array + */ + private function getDataForGreece() + { + return [ + ['GR', 'GR-A', 'Anatolikí Makedonía kai Thráki'], + ['GR', 'GR-I', 'Attikí'], + ['GR', 'GR-G', 'Dytikí Elláda'], + ['GR', 'GR-C', 'Dytikí Makedonía'], + ['GR', 'GR-F', 'Ionía Nísia'], + ['GR', 'GR-D', 'Ípeiros'], + ['GR', 'GR-B', 'Kentrikí Makedonía'], + ['GR', 'GR-M', 'Kríti'], + ['GR', 'GR-L', 'Nótio Aigaío'], + ['GR', 'GR-J', 'Pelopónnisos'], + ['GR', 'GR-H', 'Stereá Elláda'], + ['GR', 'GR-E', 'Thessalía'], + ['GR', 'GR-K', 'Vóreio Aigaío'], + + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForIceland.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForIceland.php new file mode 100644 index 0000000000000..6339b8bb71db4 --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForIceland.php @@ -0,0 +1,95 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Directory\Setup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Directory\Setup\DataInstallerFactory; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add Iceland States + */ +class AddDataForIceland implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * AddDataForIceland constructor. + * + * @param ModuleDataSetupInterface $moduleDataSetup + * @param DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForIceland() + ); + + return $this; + } + + /** + * Iceland states data. + * + * @return array + */ + private function getDataForIceland() + { + return [ + ['IS', 'IS-01', 'Höfuðborgarsvæði'], + ['IS', 'IS-02', 'Suðurnes'], + ['IS', 'IS-03', 'Vesturland'], + ['IS', 'IS-04', 'Vestfirðir'], + ['IS', 'IS-05', 'Norðurland vestra'], + ['IS', 'IS-06', 'Norðurland eystra'], + ['IS', 'IS-07', 'Austurland'], + ['IS', 'IS-08', 'Suðurland'] + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php new file mode 100644 index 0000000000000..9daeb1cf5bf1e --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php @@ -0,0 +1,107 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Directory\Setup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Directory\Setup\DataInstallerFactory; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add Portugal States + */ +class AddDataForPortugal implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * AddDataForPortugal constructor. + * + * @param ModuleDataSetupInterface $moduleDataSetup + * @param DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForPortugal() + ); + + return $this; + } + + /** + * Portugal states data. + * + * @return array + */ + private function getDataForPortugal() + { + return [ + ['PT', 'PT-01', 'Aveiro'], + ['PT', 'PT-02', 'Beja'], + ['PT', 'PT-03', 'Braga'], + ['PT', 'PT-04', 'Bragança'], + ['PT', 'PT-05', 'Castelo Branco'], + ['PT', 'PT-06', 'Coimbra'], + ['PT', 'PT-07', 'Évora'], + ['PT', 'PT-08', 'Faro'], + ['PT', 'PT-09', 'Guarda'], + ['PT', 'PT-10', 'Leiria'], + ['PT', 'PT-11', 'Lisboa'], + ['PT', 'PT-12', 'Portalegre'], + ['PT', 'PT-13', 'Porto'], + ['PT', 'PT-14', 'Santarém'], + ['PT', 'PT-15', 'Setúbal'], + ['PT', 'PT-16', 'Viana do Castelo'], + ['PT', 'PT-17', 'Vila Real'], + ['PT', 'PT-18', 'Viseu'], + ['PT', 'PT-19', 'Região Autónoma dos Açores'], + ['PT', 'PT-20', 'Região Autónoma da Madeira'] + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForSweden.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForSweden.php new file mode 100644 index 0000000000000..b4bed72a726bd --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForSweden.php @@ -0,0 +1,108 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Directory\Setup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Directory\Setup\DataInstallerFactory; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add Sweden States + */ +class AddDataForSweden implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * AddDataForSweden constructor. + * + * @param ModuleDataSetupInterface $moduleDataSetup + * @param DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForSweden() + ); + + return $this; + } + + /** + * Swedish states data. + * + * @return array + */ + private function getDataForSweden() + { + return [ + ['SE', 'SE-K', 'Blekinge län'], + ['SE', 'SE-W', 'Dalarnas län'], + ['SE', 'SE-I', 'Gotlands län'], + ['SE', 'SE-X', 'Gävleborgs län'], + ['SE', 'SE-N', 'Hallands län'], + ['SE', 'SE-Z', 'Jämtlands län'], + ['SE', 'SE-F', 'Jönköpings län'], + ['SE', 'SE-H', 'Kalmar län'], + ['SE', 'SE-G', 'Kronobergs län'], + ['SE', 'SE-BD', 'Norrbottens län'], + ['SE', 'SE-M', 'Skåne län'], + ['SE', 'SE-AB', 'Stockholms län'], + ['SE', 'SE-D', 'Södermanlands län'], + ['SE', 'SE-C', 'Uppsala län'], + ['SE', 'SE-S', 'Värmlands län'], + ['SE', 'SE-AC', 'Västerbottens län'], + ['SE', 'SE-Y', 'Västernorrlands län'], + ['SE', 'SE-U', 'Västmanlands län'], + ['SE', 'SE-O', 'Västra Götalands län'], + ['SE', 'SE-T', 'Örebro län'], + ['SE', 'SE-E', 'Östergötlands län'] + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Directory/Model/RegionTest.php b/dev/tests/integration/testsuite/Magento/Directory/Model/RegionTest.php index 774690617d861..44c8377f1eaf7 100644 --- a/dev/tests/integration/testsuite/Magento/Directory/Model/RegionTest.php +++ b/dev/tests/integration/testsuite/Magento/Directory/Model/RegionTest.php @@ -57,7 +57,13 @@ public function getCountryIdDataProvider():array ['countryId' => 'MX'], ['countryId' => 'PL'], ['countryId' => 'IT'], - ['countryId' => 'BG'] + ['countryId' => 'BG'], + ['countryId' => 'PT'], + ['countryId' => 'IS'], + ['countryId' => 'SE'], + ['countryId' => 'GR'], + ['countryId' => 'DK'], + ['countryId' => 'AL'] ]; } } From e38122ae332af8b324a14d1f93de979023a126e8 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Wed, 18 Nov 2020 13:44:15 +0200 Subject: [PATCH 071/346] fix i18n --- app/code/Magento/Sales/i18n/en_US.csv | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Sales/i18n/en_US.csv b/app/code/Magento/Sales/i18n/en_US.csv index dea0b76437ca7..c429a10411af4 100644 --- a/app/code/Magento/Sales/i18n/en_US.csv +++ b/app/code/Magento/Sales/i18n/en_US.csv @@ -284,8 +284,8 @@ Go to Home Page,Go to Home Page We can't find this wish list.,We can't find this wish list. "We could not add a product to cart by the ID ""%1"".","We could not add a product to cart by the ID ""%1""." There is an error in one of the option rows.,There is an error in one of the option rows. -Shipping Address: ,Shipping Address: -Billing Address: ,Billing Address: +"Shipping Address: ","Shipping Address: " +"Billing Address: ","Billing Address: " Please specify order items.,Please specify order items. Please specify a shipping method.,Please specify a shipping method. Please specify a payment method.,Please specify a payment method. @@ -383,8 +383,8 @@ Authorization,Authorization Please set a proper payment and order id.,Please set a proper payment and order id. Please enter a Transaction ID.,Please enter a Transaction ID. You can't do this without a transaction object.,You can't do this without a transaction object. -Order # ,Order # -Order Date: ,Order Date: +"Order # ","Order # " +"Order Date: ","Order Date: " Sold to:,Sold to: Ship to:,Ship to: Payment Method:,Payment Method: @@ -400,8 +400,8 @@ Total (ex),Total (ex) Qty,Qty Tax,Tax Total (inc),Total (inc) -Credit Memo # ,Credit Memo # -Invoice # ,Invoice # +"Credit Memo # ","Credit Memo # " +"Invoice # ","Invoice # " The order object is not specified.,The order object is not specified. The source object is not specified.,The source object is not specified. An item object is not specified.,An item object is not specified. @@ -409,7 +409,7 @@ A PDF object is not specified.,A PDF object is not specified. A PDF page object is not specified.,A PDF page object is not specified. Excl. Tax,Excl. Tax Incl. Tax,Incl. Tax -Packing Slip # ,Packing Slip # +"Packing Slip # ","Packing Slip # " title,title The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal.,The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal. We cannot register an existing shipment,We cannot register an existing shipment @@ -669,7 +669,7 @@ Your %store_name order has shipped,Your %store_name order has shipped Your shipping confirmation is below. Thank you again for your business.,Your shipping confirmation is below. Thank you again for your business. Your Shipment #%shipment_id for Order #%order_id,Your Shipment #%shipment_id for Order #%order_id Update to your %store_name shipment,Update to your %store_name shipment -Gift Options for ,Gift Options for +"Gift Options for ","Gift Options for " Add Products,Add Products You have item changes,You have item changes Ok,Ok From 5aac129b18a8d53fb5a4907029d4fc8fb1ce54f5 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 18 Nov 2020 09:03:06 -0600 Subject: [PATCH 072/346] MC-38787: Admin Product Grid Page indicator issue --- app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js index 534d292809ed1..761fcb6864fe1 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js @@ -36,7 +36,8 @@ define([ imports: { totalSelected: '${ $.selectProvider }:totalSelected', totalRecords: '${ $.provider }:data.totalRecords', - filters: '${ $.provider }:params.filters' + filters: '${ $.provider }:params.filters', + search: '${ $.provider }:params.search' }, exports: { @@ -58,7 +59,8 @@ define([ 'pages': 'onPagesChange', 'pageSize': 'onPageSizeChange', 'totalRecords': 'updateCounter', - '${ $.provider }:params.filters': 'goFirst' + '${ $.provider }:params.filters': 'goFirst', + 'search': 'goFirst' }, modules: { From 54788a81bbe47a963d68d4de0e2ed3732d5fda51 Mon Sep 17 00:00:00 2001 From: Zach Nanninga <zach@mediotype.com> Date: Wed, 18 Nov 2020 13:27:16 -0600 Subject: [PATCH 073/346] ISSUE-30286 - Change layout update removal button rendering from a block to directly in the template to prevent inaccurate js element selection in SecureHtmlRenderer event listener generation. --- .../Widget/Instance/Edit/Tab/Main/Layout.php | 19 ------------------- .../templates/instance/edit/layout.phtml | 3 ++- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php b/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php index c48bf9e7e4c7a..a704a5676f632 100644 --- a/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php +++ b/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php @@ -315,25 +315,6 @@ public function getAddLayoutButtonHtml() return $button->toHtml(); } - /** - * Retrieve remove layout button html - * - * @return string - */ - public function getRemoveLayoutButtonHtml() - { - $button = $this->getLayout()->createBlock( - \Magento\Backend\Block\Widget\Button::class - )->setData( - [ - 'label' => $this->escapeHtmlAttr(__('Remove Layout Update')), - 'onclick' => 'WidgetInstance.removePageGroup(this)', - 'class' => 'action-delete', - ] - ); - return $button->toHtml(); - } - /** * Prepare and retrieve page groups data of widget instance * 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 93c5cac33f947..2d4f88709fd91 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 @@ -38,7 +38,8 @@ var pageGroupTemplate = '<div class="fieldset-wrapper page_group_container" id=" '<label for="widget_instance[<%- data.id %>][page_group]">Display on <span class="required">*</span></label>'+ '{$block->getDisplayOnSelectHtml()}'+ '<div class="actions">'+ - {$jsonHelper->jsonEncode($block->getRemoveLayoutButtonHtml())} + + '<button title="{$escaper->escapeHtmlAttr(__('Remove Layout Update'))}" type="button"'+ + ' class="action-default scalable action-delete" onclick="WidgetInstance.removePageGroup(this)" />'+ '</div>'+ '</div>'+ '<div class="fieldset-wrapper-content">'+ From 9d6eb3c3167df12f56bd791c2429ed04eba6f9b4 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 18 Nov 2020 14:15:29 -0600 Subject: [PATCH 074/346] MC-38787: Admin Product Grid Page indicator issue --- app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js index 761fcb6864fe1..0f5a9289b71ff 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js @@ -186,7 +186,7 @@ define([ * @returns {Paging} Chainable. */ goFirst: function () { - if (!_.isUndefined(this.filters)) { + if (!_.isUndefined(this.filters) || !_.isEmpty(this.search)) { this.current = 1; } From f756a57f02788a2d25cd6e653c8ec3c27b826904 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 18 Nov 2020 16:59:57 -0600 Subject: [PATCH 075/346] MC-38787: Admin Product Grid Page indicator issue --- app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js index 0f5a9289b71ff..761fcb6864fe1 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js @@ -186,7 +186,7 @@ define([ * @returns {Paging} Chainable. */ goFirst: function () { - if (!_.isUndefined(this.filters) || !_.isEmpty(this.search)) { + if (!_.isUndefined(this.filters)) { this.current = 1; } From 2fbfb1fc1e99da956a1ac579e63eb1af1adce90e Mon Sep 17 00:00:00 2001 From: lykhachov <ilyalykhachov.com.ua> Date: Thu, 19 Nov 2020 10:07:47 +0200 Subject: [PATCH 076/346] added "changelog" to whitelist --- .../static/testsuite/Magento/Test/Legacy/_files/words_ce.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml index 92e7b15efed29..ccad52fae453e 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml @@ -73,5 +73,9 @@ <path>app/design/adminhtml/Magento/backend/Magento_Rma/web/css/source/_module.less</path> <word>rma</word> </item> + <item> + <path>app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php</path> + <word>changelog</word> + </item> </whitelist> </config> From 8cfc5393e16b818ef0ade5fc6a8c32b225bdbffd Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 19 Nov 2020 16:19:27 +0200 Subject: [PATCH 077/346] adding AdminFillAccountInformationOnCreateOrderPageActionGroup --- ...nformationOnCreateOrderPageActionGroup.xml | 19 +++++++++++++++++++ ...vailabilityCreditMemoWithNoPaymentTest.xml | 6 ++++-- ...reateOrderWithMinimumAmountEnabledTest.xml | 8 +++++--- ...ubmitsOrderPaymentMethodValidationTest.xml | 8 +++++--- ...minSubmitsOrderWithAndWithoutEmailTest.xml | 6 ++++-- ...rderWithAndWithoutFieldsValidationTest.xml | 6 ++++-- .../Test/AdminCheckingTaxReportGridTest.xml | 6 ++++-- 7 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminFillAccountInformationOnCreateOrderPageActionGroup.xml diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminFillAccountInformationOnCreateOrderPageActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminFillAccountInformationOnCreateOrderPageActionGroup.xml new file mode 100644 index 0000000000000..acf4ff8b43eca --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminFillAccountInformationOnCreateOrderPageActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFillAccountInformationOnCreateOrderPageActionGroup"> + <arguments> + <argument name="group" defaultValue="{{GeneralCustomerGroup.code}}" type="string"/> + <argument name="email" type="string"/> + </arguments> + <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{group}}" stepKey="selectCustomerGroup"/> + <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{email}}" stepKey="fillCustomerEmail"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml index 182549a6fe301..4379fc283510d 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml @@ -61,8 +61,10 @@ <click selector="{{AdminOrderFormItemsSection.updateItemsAndQuantities}}" stepKey="clickUpdateItemsAndQuantitiesButton"/> <!--Fill customer group and customer email--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup"/> - <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail"/> + <comment userInput="Fill Account Information" stepKey="selectCustomerGroup"/> + <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail"> + <argument name="email" value="{{Simple_US_Customer.email}}"/> + </actionGroup> <!--Fill customer address information--> <actionGroup ref="FillOrderCustomerInformationActionGroup" stepKey="fillCustomerAddress"> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml index b5c9e9443d1f9..2d8b8e9b8fb46 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml @@ -45,9 +45,11 @@ </actionGroup> <!--Fill customer group information--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectGroup"/> - <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillEmail"/> - + <comment userInput="Fill Account Information" stepKey="selectGroup"/> + <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillEmail"> + <argument name="email" value="{{Simple_US_Customer.email}}"/> + </actionGroup> + <!--Fill customer address information--> <actionGroup ref="FillOrderCustomerInformationActionGroup" stepKey="fillCustomerAddress"> <argument name="customer" value="Simple_US_Customer"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml index bd6a21e3112ca..5956a1a619fab 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml @@ -48,9 +48,11 @@ <scrollToTopOfPage stepKey="scrollToTopOfOrderFormPage" after="seePaymentMethodRequired"/> <!--Fill customer group and customer email--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="scrollToTopOfOrderFormPage"/> - <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail" after="selectCustomerGroup"/> - + <comment userInput="Fill Account Information" stepKey="selectCustomerGroup"/> + <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail"> + <argument name="email" value="{{Simple_US_Customer.email}}"/> + </actionGroup> + <!--Fill customer address information--> <actionGroup ref="FillOrderCustomerInformationActionGroup" stepKey="fillCustomerAddress" after="fillCustomerEmail"> <argument name="customer" value="Simple_US_Customer"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml index 727aef99352ec..215c888833885 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml @@ -46,8 +46,10 @@ </actionGroup> <!--Fill customer group and customer email--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> - <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail" after="selectCustomerGroup"/> + <comment userInput="Fill Account Information" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> + <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail" after="selectCustomerGroup"> + <argument name="email" value="{{Simple_US_Customer.email}}"/> + </actionGroup> <!--Fill customer address information--> <actionGroup ref="FillOrderCustomerInformationActionGroup" stepKey="fillCustomerAddress" after="fillCustomerEmail"> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml index 2bedb16f3d1dc..48ce356a43174 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml @@ -45,8 +45,10 @@ </actionGroup> <!--Fill customer group and customer email--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> - <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail" after="selectCustomerGroup"/> + <comment userInput="Fill Account Information" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> + <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail" after="selectCustomerGroup"> + <argument name="email" value="{{Simple_US_Customer.email}}"/> + </actionGroup> <!--Fill wrong customer address information--> <actionGroup ref="FillOrderCustomerInformationActionGroup" stepKey="fillWrongCustomerAddress" after="fillCustomerEmail"> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml index 84278468a0590..61482d7f5a567 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml @@ -154,8 +154,10 @@ </actionGroup> <!--Fill customer group and customer email--> - <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectCustomerGroup"/> - <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail"/> + <comment userInput="Fill Account Information" stepKey="selectCustomerGroup"/> + <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail"> + <argument name="email" value="{{Simple_US_Customer.email}}"/> + </actionGroup> <!--Fill customer address information--> <actionGroup ref="FillOrderCustomerInformationActionGroup" stepKey="fillCustomerAddress"> From b2a767dcd923431b6f624b13c840556cb2d29196 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 19 Nov 2020 16:31:12 +0200 Subject: [PATCH 078/346] updating before/after attributes in AdminSubmitsOrderPaymentMethodValidationTest --- .../Test/AdminSubmitsOrderPaymentMethodValidationTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml index 5956a1a619fab..1e09f308018d2 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml @@ -48,8 +48,8 @@ <scrollToTopOfPage stepKey="scrollToTopOfOrderFormPage" after="seePaymentMethodRequired"/> <!--Fill customer group and customer email--> - <comment userInput="Fill Account Information" stepKey="selectCustomerGroup"/> - <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail"> + <comment userInput="Fill Account Information" stepKey="selectCustomerGroup" after="scrollToTopOfOrderFormPage"/> + <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail" after="selectCustomerGroup"> <argument name="email" value="{{Simple_US_Customer.email}}"/> </actionGroup> From 1089f15b276cbbe30c2279349a934716148321be Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 19 Nov 2020 19:08:10 +0200 Subject: [PATCH 079/346] restoring stepKeys --- .../AddOutOfStockProductToCompareListTest.xml | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml index b2fbf2ae3810a..c28c5a040e553 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml @@ -38,15 +38,21 @@ <deleteData createDataKey="product" stepKey="deleteProduct"/> <deleteData createDataKey="category" stepKey="deleteCategory"/> </after> + <comment userInput="Open product page | Comment is kept to preserve the step key for backward compatibility" stepKey="openProdPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="goToSimpleProductPage"/> - <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductStorefront"> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="waitForSimpleProductPage"> <argument name="productUrl" value="$$product.custom_attributes[url_key]$$"/> </actionGroup> - + + <comment userInput="'Add to compare' link is not available | Comment is kept to preserve the step key for backward compatibility" stepKey="addToCompareLinkAvailability"/> + <dontSeeElement selector="{{StorefrontProductInfoMainSection.productAddToCompare}}" stepKey="dontSeeAddToCompareLink"/> + <comment userInput="Turn on 'out of stock' config | Comment is kept to preserve the step key for backward compatibility" stepKey="onOutOfStockConfig"/> <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockEnable.path}} {{CatalogInventoryOptionsShowOutOfStockEnable.value}}" stepKey="setConfigShowOutOfStockTrue"/> + <comment userInput="Clear cache and reindex | Comment is kept to preserve the step key for backward compatibility" stepKey="cleanCache"/> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> <argument name="indices" value=""/> </actionGroup> @@ -54,41 +60,67 @@ <argument name="tags" value=""/> </actionGroup> - <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openProductStorefront1"> + <comment userInput="Open product page | Comment is kept to preserve the step key for backward compatibility" stepKey="openProductPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="goToSimpleProductPage2"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForSimpleProductPage2"/> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="seeAddToCompareLink"> <argument name="productUrl" value="$$product.custom_attributes[url_key]$$"/> </actionGroup> + + <comment userInput="Click on 'Add to Compare' link | Comment is kept to preserve the step key for backward compatibility" stepKey="clickOnAddToCompareLink"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickOnAddToCompare"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForProdAddToCmpList"/> + <comment userInput="Assert success message | Comment is kept to preserve the step key for backward compatibility" stepKey="assertSuccessMsg"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="grabTextFromSuccessMessage"/> - <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="addProductToCompare1"> + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="assertSuccessMessage"> <argument name="productVar" value="$$product$$"/> </actionGroup> - <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="openCategoryPage"> + <comment userInput="See product in the comparison list | Comment is kept to preserve the step key for backward compatibility" stepKey="seeProductInComparisonList"/> + + <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="openCategoryPage"> <argument name="categoryName" value="$$category.name$$"/> </actionGroup> - <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="compareOpenComparePage"/> + <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="navigateToComparePage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForStorefrontProductComparePageLoad"/> - <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInComparisonList"> + <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInCompareList"> <argument name="productVar" value="$$product$$"/> </actionGroup> - <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="openCategoryPage1"> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="deleteProdFromCmpList"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="onCategoryPage"/> + <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="waitForPageLoad1"> <argument name="categoryName" value="$$category.name$$"/> </actionGroup> - <actionGroup ref="StorefrontClearCompareActionGroup" stepKey="clearList"/> + <actionGroup ref="StorefrontClearCompareActionGroup" stepKey="clickClearAll"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForConfirmPageLoad"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="confirmProdDelate"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForConfirmLoad"/> + <comment userInput="Add product to compare list fom Category page | Comment is kept to preserve the step key for backward compatibility" stepKey="addToCmpFromCategPage"/> - <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverOverProduct"/> - <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="addProductToCompare2"> + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="clickAddToCompare"> <argument name="productVar" value="$$product$$"/> </actionGroup> - + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitProdAddingToCmpList"/> + <comment userInput="Assert success message | Comment is kept to preserve the step key for backward compatibility" stepKey="assertSuccessMsg2"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="grabTextFromSuccessMessage2"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="assertSuccessMessage2"/> + + <comment userInput="Check that product displays on add to compare widget | Comment is kept to preserve the step key for backward compatibility" stepKey="checkProdNameOnWidget"/> <seeElement selector="{{StorefrontComparisonSidebarSection.ProductTitleByName($$product.name$$)}}" stepKey="seeProdNameOnCmpWidget"/> - <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="compareOpenComparePage1"/> + <comment userInput="See product in the compare page" stepKey="seeProductInComparePage"/> + <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="navigateToComparePage2"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForStorefrontProductComparePageLoad2"/> - <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInComparisonList1"> + <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInCompareList2"> <argument name="productVar" value="$$product$$"/> </actionGroup> From 6e5d886359a298de1f8ee43c067ac3be6b6e5c6d Mon Sep 17 00:00:00 2001 From: Andrii Kasian <akasian@magento.com> Date: Thu, 19 Nov 2020 13:13:27 -0600 Subject: [PATCH 080/346] Allow to generate big number of customer on galera cluster --- .../FixtureGenerator/CustomerGenerator.php | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/setup/src/Magento/Setup/Model/FixtureGenerator/CustomerGenerator.php b/setup/src/Magento/Setup/Model/FixtureGenerator/CustomerGenerator.php index e2b11c3dc7eb3..f20060e15c2b1 100644 --- a/setup/src/Magento/Setup/Model/FixtureGenerator/CustomerGenerator.php +++ b/setup/src/Magento/Setup/Model/FixtureGenerator/CustomerGenerator.php @@ -124,24 +124,31 @@ private function getCustomerAddressEntityHandler() */ private function addDefaultAddresses() { - $this->getConnection()->query( - sprintf( - ' - update `%s` customer - join ( - select - parent_id, min(entity_id) as min, max(entity_id) as max - from `%s` - group by parent_id - ) customer_address on customer_address.parent_id = customer.entity_id + $batchSize = 10000; + $customerTableName = $this->resourceConnection->getTableName('customer_entity'); + $customerAddressTableName = $this->resourceConnection->getTableName('customer_address_entity'); + $customerMaxId = $this->getConnection()->fetchOne("select max(entity_id) from `$customerTableName`"); + for ($i = 1; $i < $customerMaxId; $i += $batchSize) { + $this->getConnection()->query( + " + update `$customerTableName` customer + join ( + select + parent_id, min(entity_id) as min, max(entity_id) as max + from `$customerAddressTableName` + group by parent_id + ) customer_address on customer_address.parent_id = customer.entity_id set customer.default_billing = customer_address.min, customer.default_shipping = customer_address.max - ', - $this->resourceConnection->getTableName('customer_entity'), - $this->resourceConnection->getTableName('customer_address_entity') - ) - ); + where entity_id between :min and :max + ", + [ + 'min' => $i, + 'max' => $i + $batchSize + ] + ); + } } /** From 1921d68f1d57924e089d794ae72e4724107383b0 Mon Sep 17 00:00:00 2001 From: Zach Nanninga <zach@mediotype.com> Date: Thu, 19 Nov 2020 14:51:43 -0600 Subject: [PATCH 081/346] ISSU-30286 - Update MFTF widget test to confirm add layout / remove layout buttons work as expected. --- .../Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml | 4 ++++ .../Widget/Test/Mftf/Section/AdminNewWidgetSection.xml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml index e657b3eb73b53..5cf135f158130 100644 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetActionGroup.xml @@ -23,6 +23,10 @@ <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate2"/> + <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.layoutUpdate}}" stepKey="seeTwoLayoutUpdates"/> + <click selector="{{AdminNewWidgetSection.removeLastLayoutUpdate}}" stepKey="clickRemoveLastLayoutUpdate"/> + <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.layoutUpdate}}" stepKey="seeOneLayoutUpdate"/> <selectOption selector="{{AdminNewWidgetSection.selectDisplayOn}}" userInput="{{widget.display_on}}" stepKey="setDisplayOn"/> <waitForAjaxLoad stepKey="waitForLoad"/> <selectOption selector="{{AdminNewWidgetSection.selectContainer}}" userInput="{{widget.container}}" stepKey="setContainer"/> diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 8a17b589d7ab2..217375fb85a19 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -17,6 +17,8 @@ <element name="widgetStoreIds" type="select" selector="#store_ids"/> <element name="widgetSortOrder" type="input" selector="#sort_order"/> <element name="addLayoutUpdate" type="button" selector=".action-default.scalable.action-add"/> + <element name="layoutUpdate" type="block" selector=".page_group_container"/> + <element name="removeLastLayoutUpdate" type="button" selector=".page_group_container:last-child .action-default.scalable.action-delete"/> <element name="selectDisplayOn" type="select" selector="#widget_instance[0][page_group]"/> <element name="selectContainer" type="select" selector="#all_pages_0>table>tbody>tr>td:nth-child(1)>div>div>select"/> <element name="displayOnByIndex" type="select" selector="select[name='widget_instance[{{index}}][page_group]']" parameterized="true"/> From b02cc2ba14c3b26c764052a4b76a01f35fc635e8 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Wed, 18 Nov 2020 16:40:23 -0600 Subject: [PATCH 082/346] MC-39134: Custom options date is not populated when editing reorder items - Fix custom date option is not populated when editing quote item after enabling javascript calendar --- .../Block/Product/View/Options/Type/Date.php | 90 ++++- .../Product/View/Options/Type/DateTest.php | 324 ++++++++++++++++++ 2 files changed, 406 insertions(+), 8 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php diff --git a/app/code/Magento/Catalog/Block/Product/View/Options/Type/Date.php b/app/code/Magento/Catalog/Block/Product/View/Options/Type/Date.php index 3a9d81eed4221..af921959f8e27 100644 --- a/app/code/Magento/Catalog/Block/Product/View/Options/Type/Date.php +++ b/app/code/Magento/Catalog/Block/Product/View/Options/Type/Date.php @@ -5,6 +5,11 @@ */ namespace Magento\Catalog\Block\Product\View\Options\Type; +use DateTimeZone; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Data\Form\FilterFactory; +use Magento\Framework\Stdlib\DateTime; + /** * Product options text type block * @@ -27,22 +32,30 @@ class Date extends \Magento\Catalog\Block\Product\View\Options\AbstractOptions */ protected $_catalogProductOptionTypeDate; + /** + * @var FilterFactory + */ + private $filterFactory; + /** * @param \Magento\Framework\View\Element\Template\Context $context * @param \Magento\Framework\Pricing\Helper\Data $pricingHelper * @param \Magento\Catalog\Helper\Data $catalogData * @param \Magento\Catalog\Model\Product\Option\Type\Date $catalogProductOptionTypeDate * @param array $data + * @param FilterFactory|null $filterFactory */ public function __construct( \Magento\Framework\View\Element\Template\Context $context, \Magento\Framework\Pricing\Helper\Data $pricingHelper, \Magento\Catalog\Helper\Data $catalogData, \Magento\Catalog\Model\Product\Option\Type\Date $catalogProductOptionTypeDate, - array $data = [] + array $data = [], + ?FilterFactory $filterFactory = null ) { $this->_catalogProductOptionTypeDate = $catalogProductOptionTypeDate; parent::__construct($context, $pricingHelper, $catalogData, $data); + $this->filterFactory = $filterFactory ?? ObjectManager::getInstance()->get(FilterFactory::class); } /** @@ -77,14 +90,24 @@ public function getDateHtml() public function getCalendarDateHtml() { $option = $this->getOption(); - $value = $this->getProduct()->getPreconfiguredValues()->getData('options/' . $option->getId() . '/date'); + $values = $this->getProduct()->getPreconfiguredValues()->getData('options/' . $option->getId()); $yearStart = $this->_catalogProductOptionTypeDate->getYearStart(); $yearEnd = $this->_catalogProductOptionTypeDate->getYearEnd(); - $dateFormat = $this->_localeDate->getDateFormat(\IntlDateFormatter::SHORT); + $dateFormat = $this->_localeDate->getDateFormatWithLongYear(); /** Escape RTL characters which are present in some locales and corrupt formatting */ $escapedDateFormat = preg_replace('/[^MmDdYy\/\.\-]/', '', $dateFormat); + $value = null; + if (is_array($values)) { + $date = $this->getInternalDateString($values); + if ($date !== null) { + $dateFilter = $this->filterFactory->create('date', ['format' => $escapedDateFormat]); + $value = $dateFilter->outputFilter($date); + } elseif (isset($values['date'])) { + $value = $values['date']; + } + } $calendar = $this->getLayout()->createBlock( \Magento\Framework\View\Element\Html\Date::class )->setId( @@ -158,8 +181,8 @@ public function getTimeHtml() * Return drop-down html with range of values * * @param string $name Id/name of html select element - * @param int $from Start position - * @param int $to End position + * @param int $from Start position + * @param int $to End position * @param int|null $value Value selected * @return string Formatted Html */ @@ -209,9 +232,8 @@ protected function _getHtmlSelect($name, $value = null) $select->setExtraParams($extraParams); if ($value === null) { - $value = $this->getProduct()->getPreconfiguredValues()->getData( - 'options/' . $option->getId() . '/' . $name - ); + $values = $this->getProduct()->getPreconfiguredValues()->getData('options/' . $option->getId()); + $value = is_array($values) ? $this->parseDate($values, $name) : null; } if ($value !== null) { $select->setValue($value); @@ -233,4 +255,56 @@ protected function _getValueWithLeadingZeros($value) } return $value < 10 ? '0' . $value : $value; } + + /** + * Get internal date format of provided value + * + * @param array $value + * @return string|null + */ + private function getInternalDateString(array $value): ?string + { + $result = null; + if (!empty($value['date']) && !empty($value['date_internal'])) { + $dateTimeZone = new DateTimeZone($this->_localeDate->getConfigTimezone()); + $dateTimeObject = date_create_from_format( + DateTime::DATETIME_PHP_FORMAT, + $value['date_internal'], + $dateTimeZone + ); + if ($dateTimeObject !== false) { + $result = $dateTimeObject->format(DateTime::DATE_PHP_FORMAT); + } + } elseif (!empty($value['day']) && !empty($value['month']) && !empty($value['year'])) { + $dateTimeObject = $this->_localeDate->date(); + $dateTimeObject->setDate((int) $value['year'], (int) $value['month'], (int) $value['day']); + $result = $dateTimeObject->format(DateTime::DATE_PHP_FORMAT); + } + return $result; + } + + /** + * Parse option value and return the requested part + * + * @param array $value + * @param string $part [year, month, day, hour, minute, day_part] + * @return string|null + */ + private function parseDate(array $value, string $part): ?string + { + $result = null; + if (!empty($value['date']) && !empty($value['date_internal'])) { + $formatDate = explode(' ', $value['date_internal']); + $date = explode('-', $formatDate[0]); + $value['year'] = $date[0]; + $value['month'] = $date[1]; + $value['day'] = $date[2]; + } + + if (isset($value[$part])) { + $result = (string) $value[$part]; + } + + return $result; + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php new file mode 100644 index 0000000000000..91a54d8fc13fa --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php @@ -0,0 +1,324 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Block\Product\View\Options\Type; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Helper\Product as ProductHelper; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Option; +use Magento\Framework\DataObjectFactory; +use Magento\Framework\Locale\ResolverInterface; +use Magento\Framework\Pricing\Render; +use Magento\Framework\View\LayoutInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + */ +class DateTest extends TestCase +{ + /** + * @var Date + */ + private $block; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var DataObjectFactory + */ + private $dataObjectFactory; + + /** + * @var ProductHelper + */ + private $productHelper; + + /** + * @var ResolverInterface + */ + private $localeResolver; + + /** + * @var string + */ + private $defaultLocale; + + /** + * @inheritDoc + */ + protected function setUp(): void + { + $objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $objectManager->get(ProductRepositoryInterface::class); + $this->productHelper = $objectManager->get(ProductHelper::class); + $this->dataObjectFactory = $objectManager->get(DataObjectFactory::class); + $layout = $objectManager->get(LayoutInterface::class); + $this->localeResolver = $objectManager->get(ResolverInterface::class); + $this->defaultLocale = $this->localeResolver->getLocale(); + $this->block = $layout->createBlock( + Date::class, + 'product.info.options.date', + [ + 'data' => [ + 'template' => 'Magento_Catalog::product/view/options/type/date.phtml' + ] + ] + ); + $layout->createBlock( + Render::class, + 'product.price.render.default', + [ + 'data' => [ + 'price_render_handle' => 'catalog_product_prices', + 'use_link_for_as_low_as' => true, + ], + ] + ); + } + + /** + * @inheritDoc + */ + protected function tearDown(): void + { + $this->localeResolver->setLocale($this->defaultLocale); + parent::tearDown(); + } + + /** + * @magentoAppArea frontend + * @param array $data + * @param array $expected + * @dataProvider toHtmlWithDropDownDataProvider + */ + public function testToHtmlWithDropDown(array $data, array $expected): void + { + $this->prepareBlock($data); + $this->assertXPaths($expected); + } + + /** + * @magentoAppArea frontend + * @magentoConfigFixture current_store catalog/custom_options/use_calendar 1 + * @param array $data + * @param array $expected + * @param string|null $locale + * @dataProvider toHtmlWithCalendarDataProvider + */ + public function testToHtmlWithCalendar(array $data, array $expected, ?string $locale = null): void + { + if ($locale) { + $this->localeResolver->setLocale($locale); + } + $this->prepareBlock($data); + $this->assertXPaths($expected); + } + + /** + * @param array $expected + */ + private function assertXPaths(array $expected): void + { + $html = $this->block->toHtml(); + $domXpath = new \DOMXPath($this->getHtmlDocument($html)); + foreach ($expected as $xpath => $value) { + $xpath = strtr($xpath, ['{id}' => $this->block->getOption()->getId()]); + $nodes = $domXpath->query(strtr($xpath, ['{id}' => $this->block->getOption()->getId()])); + $this->assertEquals(1, $nodes->count(), 'Cannot find element \'' . $xpath . '"\' in the HTML'); + $this->assertEquals($value, $nodes->item(0)->getAttribute('value')); + } + } + + /** + * @param array $data + */ + private function prepareBlock(array $data): void + { + /** @var Product $product */ + $product = $this->productRepository->get('simple'); + $this->block->setProduct($product); + $option = $this->getDateTimeOption($product); + $this->block->setOption($option); + $buyRequest = $this->dataObjectFactory->create(); + $buyRequest->setData( + [ + 'qty' => 1, + 'options' => [ + $option->getId() => $data + ], + ] + ); + $this->productHelper->prepareProductOptions($product, $buyRequest); + } + + /** + * @param Product $product + * @return Option|null + */ + private function getDateTimeOption(Product $product): ?Option + { + $option = null; + foreach ($product->getOptions() as $customOption) { + if ($customOption->getType() === Option::OPTION_TYPE_DATE_TIME) { + $option = $customOption; + break; + } + } + return $option; + } + + /** + * @param string $source + * @return \DOMDocument + */ + private function getHtmlDocument(string $source): \DOMDocument + { + $page =<<<HTML +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Title + + +$source + + +HTML; + $domDocument = new \DOMDocument('1.0', 'UTF-8'); + libxml_use_internal_errors(true); + $domDocument->loadHTML($page); + libxml_use_internal_errors(false); + return $domDocument; + } + + /** + * @return array + */ + public function toHtmlWithDropDownDataProvider(): array + { + return [ + [ + [ + 'month' => '3', + 'day' => '5', + 'year' => '2020', + 'hour' => '2', + 'minute' => '15', + 'day_part' => 'am', + 'date_internal' => '2020-09-30 02:15:00' + ], + [ + '//select[@id="options_{id}_year"]/option[@selected]' => '2020', + '//select[@id="options_{id}_month"]/option[@selected]' => '3', + '//select[@id="options_{id}_day"]/option[@selected]' => '5', + '//select[@id="options_{id}_hour"]/option[@selected]' => '2', + '//select[@id="options_{id}_minute"]/option[@selected]' => '15', + '//select[@id="options_{id}_day_part"]/option[@selected]' => 'am', + ] + ], + [ + [ + 'date' => '09/30/2022', + 'hour' => '2', + 'minute' => '15', + 'day_part' => 'am', + 'date_internal' => '2020-09-30 02:15:00' + ], + [ + '//select[@id="options_{id}_year"]/option[@selected]' => '2020', + '//select[@id="options_{id}_month"]/option[@selected]' => '9', + '//select[@id="options_{id}_day"]/option[@selected]' => '30', + '//select[@id="options_{id}_hour"]/option[@selected]' => '2', + '//select[@id="options_{id}_minute"]/option[@selected]' => '15', + '//select[@id="options_{id}_day_part"]/option[@selected]' => 'am', + ] + ] + ]; + } + + /** + * @return array + */ + public function toHtmlWithCalendarDataProvider(): array + { + return [ + [ + [ + 'month' => '3', + 'day' => '5', + 'year' => '2020', + 'hour' => '2', + 'minute' => '15', + 'day_part' => 'am', + 'date_internal' => '2020-09-30 02:15:00' + ], + [ + '//input[@id="options_{id}_date"]' => '3/5/2020', + '//select[@id="options_{id}_hour"]/option[@selected]' => '2', + '//select[@id="options_{id}_minute"]/option[@selected]' => '15', + '//select[@id="options_{id}_day_part"]/option[@selected]' => 'am', + ] + ], + [ + [ + 'date' => '09/30/2022', + 'hour' => '2', + 'minute' => '15', + 'day_part' => 'am', + 'date_internal' => '2020-09-30 02:15:00' + ], + [ + '//input[@id="options_{id}_date"]' => '9/30/2020', + '//select[@id="options_{id}_hour"]/option[@selected]' => '2', + '//select[@id="options_{id}_minute"]/option[@selected]' => '15', + '//select[@id="options_{id}_day_part"]/option[@selected]' => 'am', + ] + ], + [ + [ + 'month' => '3', + 'day' => '5', + 'year' => '2020', + 'hour' => '2', + 'minute' => '15', + 'day_part' => 'am', + 'date_internal' => '2020-09-30 02:15:00' + ], + [ + '//input[@id="options_{id}_date"]' => '05/03/2020', + '//select[@id="options_{id}_hour"]/option[@selected]' => '2', + '//select[@id="options_{id}_minute"]/option[@selected]' => '15', + '//select[@id="options_{id}_day_part"]/option[@selected]' => 'am', + ], + 'fr_FR' + ], + [ + [ + 'date' => '09/30/2022', + 'hour' => '2', + 'minute' => '15', + 'day_part' => 'am', + 'date_internal' => '2020-09-30 02:15:00' + ], + [ + '//input[@id="options_{id}_date"]' => '30/09/2020', + '//select[@id="options_{id}_hour"]/option[@selected]' => '2', + '//select[@id="options_{id}_minute"]/option[@selected]' => '15', + '//select[@id="options_{id}_day_part"]/option[@selected]' => 'am', + ], + 'fr_FR' + ] + ]; + } +} From 0c3561cfb197b80982a8cbf80bfbd268a704fe98 Mon Sep 17 00:00:00 2001 From: Roman Flowers Date: Thu, 19 Nov 2020 15:38:52 -0600 Subject: [PATCH 083/346] MC-38787: Admin Product Grid Page indicator issue --- .../Magento/Ui/view/base/web/js/grid/paging/paging.js | 6 +++--- .../Magento/Ui/view/base/web/js/grid/search/search.js | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js index 761fcb6864fe1..6b6636fac5668 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js @@ -37,7 +37,7 @@ define([ totalSelected: '${ $.selectProvider }:totalSelected', totalRecords: '${ $.provider }:data.totalRecords', filters: '${ $.provider }:params.filters', - search: '${ $.provider }:params.search' + keywordUpdated: '${ $.provider }:params.keywordUpdated' }, exports: { @@ -60,7 +60,7 @@ define([ 'pageSize': 'onPageSizeChange', 'totalRecords': 'updateCounter', '${ $.provider }:params.filters': 'goFirst', - 'search': 'goFirst' + 'keywordUpdated': 'goFirst' }, modules: { @@ -186,7 +186,7 @@ define([ * @returns {Paging} Chainable. */ goFirst: function () { - if (!_.isUndefined(this.filters)) { + if ((!_.isUndefined(this.filters) && _.keys(this.filters) > 1) || this.keywordUpdated) { this.current = 1; } diff --git a/app/code/Magento/Ui/view/base/web/js/grid/search/search.js b/app/code/Magento/Ui/view/base/web/js/grid/search/search.js index 3f5434761ba18..307f3606a2e3f 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/search/search.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/search/search.js @@ -22,6 +22,7 @@ define([ placeholder: $t('Search by keyword'), label: $t('Keyword'), value: '', + keywordUpdated: false, previews: [], chipsProvider: 'componentType = filtersChips, ns = ${ $.ns }', statefull: { @@ -31,7 +32,8 @@ define([ value: true, previews: true, inputValue: true, - focused: true + focused: true, + keywordUpdated: true }, imports: { inputValue: 'value', @@ -39,7 +41,8 @@ define([ focused: false }, exports: { - value: '${ $.provider }:params.search' + value: '${ $.provider }:params.search', + keywordUpdated: '${ $.provider }:params.keywordUpdated' }, modules: { chips: '${ $.chipsProvider }' @@ -124,6 +127,7 @@ define([ apply: function (value) { value = value || this.inputValue; + this.keywordUpdated = this.value !== this.inputValue; this.value = this.inputValue = value.trim(); return this; From f1f4a861b9b516637de3b1910101a7ba406f8ea7 Mon Sep 17 00:00:00 2001 From: Roman Flowers Date: Thu, 19 Nov 2020 15:44:45 -0600 Subject: [PATCH 084/346] MC-38787: Admin Product Grid Page indicator issue --- app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js index 6b6636fac5668..a411a7c1a6837 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js @@ -60,7 +60,7 @@ define([ 'pageSize': 'onPageSizeChange', 'totalRecords': 'updateCounter', '${ $.provider }:params.filters': 'goFirst', - 'keywordUpdated': 'goFirst' + '${ $.provider }:params.search': 'goFirst' }, modules: { From 36640fd5f43c0b7bc3fc7312ff491432744148b8 Mon Sep 17 00:00:00 2001 From: Roman Flowers Date: Thu, 19 Nov 2020 15:54:26 -0600 Subject: [PATCH 085/346] MC-38787: Admin Product Grid Page indicator issue --- app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js index a411a7c1a6837..9d4461d0bdc64 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js @@ -186,7 +186,10 @@ define([ * @returns {Paging} Chainable. */ goFirst: function () { - if ((!_.isUndefined(this.filters) && _.keys(this.filters) > 1) || this.keywordUpdated) { + if ( + (!_.isUndefined(this.filters) && _.keys(this.filters) > 1) || + (!_.isUndefined(this.keywordUpdated) && this.keywordUpdated) + ) { this.current = 1; } From b5b79b71cb252a91779cc3e2f78c6cf89e3f5a13 Mon Sep 17 00:00:00 2001 From: Roman Flowers Date: Thu, 19 Nov 2020 16:21:29 -0600 Subject: [PATCH 086/346] MC-38787: Admin Product Grid Page indicator issue --- .../Ui/view/base/web/js/grid/paging/paging.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js index 9d4461d0bdc64..5f6c21cf6167f 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/paging/paging.js @@ -60,7 +60,7 @@ define([ 'pageSize': 'onPageSizeChange', 'totalRecords': 'updateCounter', '${ $.provider }:params.filters': 'goFirst', - '${ $.provider }:params.search': 'goFirst' + '${ $.provider }:params.search': 'onSearchUpdate' }, modules: { @@ -186,10 +186,7 @@ define([ * @returns {Paging} Chainable. */ goFirst: function () { - if ( - (!_.isUndefined(this.filters) && _.keys(this.filters) > 1) || - (!_.isUndefined(this.keywordUpdated) && this.keywordUpdated) - ) { + if (!_.isUndefined(this.filters)) { this.current = 1; } @@ -287,6 +284,17 @@ define([ */ onPagesChange: function () { this.updateCursor(); + }, + + /** + * Resent the pagination to Page 1 on search keyword update + */ + onSearchUpdate: function () { + if (!_.isUndefined(this.keywordUpdated) && this.keywordUpdated) { + this.goFirst(); + } + + return this; } }); }); From ff2451b8420076f7362f3b547f090024f78c0813 Mon Sep 17 00:00:00 2001 From: Sergiy Vasiutynskyi Date: Fri, 20 Nov 2020 08:49:18 +0200 Subject: [PATCH 087/346] Removed 'cache:flush' commands from tests --- .../Test/StorefrontOnlyXProductLeftForSimpleProductsTest.xml | 2 +- ...rifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml | 4 ++-- .../Test/AdminLoginAsCustomerAddProductToWishlistTest.xml | 4 ++-- .../Test/Mftf/Test/AdminLoginAsCustomerAutoDetectionTest.xml | 4 ++-- .../Test/AdminLoginAsCustomerDirectlyToCustomWebsiteTest.xml | 4 ++-- .../Test/AdminLoginAsCustomerEditCustomersAddressTest.xml | 4 ++-- ...oginAsCustomerLogNotShownIfLoginAsCustomerDisabledTest.xml | 2 +- .../Test/Mftf/Test/AdminLoginAsCustomerLoggingTest.xml | 4 ++-- .../AdminLoginAsCustomerManualChooseFromOrderPageTest.xml | 4 ++-- .../Test/Mftf/Test/AdminLoginAsCustomerManualChooseTest.xml | 4 ++-- .../Test/AdminLoginAsCustomerMultishippingLoggingTest.xml | 4 ++-- .../Test/Mftf/Test/AdminLoginAsCustomerPlaceOrderTest.xml | 4 ++-- .../Test/Mftf/Test/AdminLoginAsCustomerReorderTest.xml | 4 ++-- .../Test/AdminLoginAsCustomerSubscribeToNewsletterTest.xml | 4 ++-- .../Test/Mftf/Test/AdminLoginAsCustomerUserLogoutTest.xml | 4 ++-- .../Mftf/Test/AdminLoginAsCustomerUserSingleSessionTest.xml | 4 ++-- .../Mftf/Test/AdminNoAccessToLoginAsCustomerButtonTest.xml | 4 ++-- .../Test/AdminNoAccessToLoginAsCustomerConfigurationTest.xml | 4 ++-- .../Test/AdminUINotShownIfLoginAsCustomerDisabledTest.xml | 2 +- .../Test/StorefrontLoginAsCustomerNotificationBannerTest.xml | 4 ++-- 20 files changed, 37 insertions(+), 37 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontOnlyXProductLeftForSimpleProductsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontOnlyXProductLeftForSimpleProductsTest.xml index dc608a7f12dd3..2063054a94d0b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontOnlyXProductLeftForSimpleProductsTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontOnlyXProductLeftForSimpleProductsTest.xml @@ -23,7 +23,7 @@ - + diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml index d529c6dd3ecc3..fc9eb8529da6f 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml +++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml @@ -18,7 +18,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAddProductToWishlistTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAddProductToWishlistTest.xml index c083383dd8861..f5919c6ccbb80 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAddProductToWishlistTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAddProductToWishlistTest.xml @@ -23,7 +23,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -38,7 +38,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAutoDetectionTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAutoDetectionTest.xml index 1175103395427..09e48b5c61aaf 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAutoDetectionTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerAutoDetectionTest.xml @@ -28,7 +28,7 @@ - + @@ -43,7 +43,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerDirectlyToCustomWebsiteTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerDirectlyToCustomWebsiteTest.xml index f9418a9cf1e1b..3b2f61339b921 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerDirectlyToCustomWebsiteTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerDirectlyToCustomWebsiteTest.xml @@ -26,7 +26,7 @@ - + @@ -60,7 +60,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerEditCustomersAddressTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerEditCustomersAddressTest.xml index cf90f0b6a8511..3a80bbb7a6f2e 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerEditCustomersAddressTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerEditCustomersAddressTest.xml @@ -23,7 +23,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -32,7 +32,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLogNotShownIfLoginAsCustomerDisabledTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLogNotShownIfLoginAsCustomerDisabledTest.xml index 4ef72d949065d..e4a6767ce7b22 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLogNotShownIfLoginAsCustomerDisabledTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLogNotShownIfLoginAsCustomerDisabledTest.xml @@ -19,7 +19,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLoggingTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLoggingTest.xml index 5b5e9e21113c8..6ae6ddfeccb47 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLoggingTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerLoggingTest.xml @@ -24,7 +24,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -40,7 +40,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseFromOrderPageTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseFromOrderPageTest.xml index e4f0209c55233..8493fda17636a 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseFromOrderPageTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseFromOrderPageTest.xml @@ -29,7 +29,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -54,7 +54,7 @@ stepKey="disableLoginAsCustomer"/> - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseTest.xml index 5f706a814eb71..551139fb8095e 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerManualChooseTest.xml @@ -25,7 +25,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -50,7 +50,7 @@ stepKey="disableLoginAsCustomer"/> - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml index 79c7571a08cfb..bde6f34e86f1a 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml @@ -30,7 +30,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -44,7 +44,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerPlaceOrderTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerPlaceOrderTest.xml index 8169b9df4c43d..8afaaabbc92bf 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerPlaceOrderTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerPlaceOrderTest.xml @@ -23,7 +23,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -59,7 +59,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerReorderTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerReorderTest.xml index 11d622319af33..8bef9fce9995b 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerReorderTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerReorderTest.xml @@ -23,7 +23,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -59,7 +59,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerSubscribeToNewsletterTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerSubscribeToNewsletterTest.xml index bc4c4adc3ac5a..1c3ae6e790089 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerSubscribeToNewsletterTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerSubscribeToNewsletterTest.xml @@ -23,7 +23,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -31,7 +31,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserLogoutTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserLogoutTest.xml index e7b5de55a56cb..ae99a4dda5593 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserLogoutTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserLogoutTest.xml @@ -24,7 +24,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -33,7 +33,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserSingleSessionTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserSingleSessionTest.xml index 5bbc218e0a948..51a4d1cf9fbed 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserSingleSessionTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerUserSingleSessionTest.xml @@ -22,7 +22,7 @@ - + @@ -33,7 +33,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerButtonTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerButtonTest.xml index 50513797d06e9..9c95ab3c3c5cc 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerButtonTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerButtonTest.xml @@ -24,7 +24,7 @@ - + @@ -67,7 +67,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerConfigurationTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerConfigurationTest.xml index d48f167656301..4032aff6d122f 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerConfigurationTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminNoAccessToLoginAsCustomerConfigurationTest.xml @@ -26,7 +26,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -70,7 +70,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUINotShownIfLoginAsCustomerDisabledTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUINotShownIfLoginAsCustomerDisabledTest.xml index e1ea363bdf6bc..10bff7c2ef68f 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUINotShownIfLoginAsCustomerDisabledTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminUINotShownIfLoginAsCustomerDisabledTest.xml @@ -19,7 +19,7 @@ - + diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/StorefrontLoginAsCustomerNotificationBannerTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/StorefrontLoginAsCustomerNotificationBannerTest.xml index 351a3c569ce24..6a83e820039d8 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/StorefrontLoginAsCustomerNotificationBannerTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/StorefrontLoginAsCustomerNotificationBannerTest.xml @@ -24,7 +24,7 @@ stepKey="enableLoginAsCustomer"/> - + @@ -32,7 +32,7 @@ - + From 2baf801a9e34f1be2aee737663ad6d5a1f47574c Mon Sep 17 00:00:00 2001 From: saphaljha Date: Fri, 11 Sep 2020 11:01:41 +0530 Subject: [PATCH 088/346] Fixed issue when using dynamic elements --- .../View/Helper/SecureHtmlRenderer.php | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index ae8ab3f15bc96..d7369416f44bf 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -111,16 +111,21 @@ public function renderEventListenerAsTag( function {$listenerFunction} () { {$attributeJavascript}; } - var {$elementName} = document.querySelector("{$elementSelector}"); - if ({$elementName}) { - {$elementName}.{$eventName} = function (event) { - var targetElement = {$elementName}; - if (event && event.target) { - targetElement = event.target; + var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); + + {$elementName}Array.forEach(function(element){ + if (element) { + element.{$eventName} = function (event) { + var targetElement = element; + if (event && event.target) { + targetElement = event.target; + } + {$listenerFunction}.apply(targetElement); } - {$listenerFunction}.apply(targetElement); } - } + }); + + script; return $this->renderTag('script', ['type' => 'text/javascript'], $script, false); From bedee3d6471396b4a04e27d53d42568ee796714f Mon Sep 17 00:00:00 2001 From: saphaljha Date: Sat, 12 Sep 2020 20:06:59 +0530 Subject: [PATCH 089/346] Updated code for validate empty nodeList and covered MFTF --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 +++++++++++++++++++ .../Mftf/Section/AdminNewWidgetSection.xml | 2 + ...AddAndDeleteMultipleLayoutSectionsTest.xml | 36 ++++++++++++++++++ .../View/Helper/SecureHtmlRenderer.php | 22 +++++------ 4 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml new file mode 100644 index 0000000000000..b7ebd09c2fcc6 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml @@ -0,0 +1,38 @@ + + + + + + Goes to the Admin Widget creation page. Add and delete multiple layouts + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index 8a17b589d7ab2..fecad673e494e 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -52,6 +52,8 @@ + + diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml new file mode 100644 index 0000000000000..5a5652e1e9049 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml @@ -0,0 +1,36 @@ + + + + + + + + + <description value="Admin should be able to Add and Delete multiple layouts"/> + <severity value="CRITICAL"/> + <group value="Widget"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToContentWidgetsPageFirst"> + <argument name="menuUiId" value="{{AdminMenuContent.dataUiId}}"/> + <argument name="submenuUiId" value="{{AdminMenuContentElementsWidgets.dataUiId}}"/> + </actionGroup> + <actionGroup ref="AdminAssertPageTitleActionGroup" stepKey="seePageTitleFirst"> + <argument name="title" value="{{AdminMenuContentElementsWidgets.pageTitle}}"/> + </actionGroup> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> + <actionGroup ref="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup" stepKey="addWidgetForTest"> + <argument name="widget" value="ProductsListWidget"/> + </actionGroup> + </test> +</tests> diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index d7369416f44bf..ebc4b8870538f 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -112,19 +112,19 @@ function {$listenerFunction} () { {$attributeJavascript}; } var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); - - {$elementName}Array.forEach(function(element){ - if (element) { - element.{$eventName} = function (event) { - var targetElement = element; - if (event && event.target) { - targetElement = event.target; + if({$elementName}Array.lenght !== 'undefined'){ + {$elementName}Array.forEach(function(element){ + if (element) { + element.{$eventName} = function (event) { + var targetElement = element; + if (event && event.target) { + targetElement = event.target; + } + {$listenerFunction}.apply(targetElement); } - {$listenerFunction}.apply(targetElement); } - } - }); - + }); + } script; From e03e17ea488b91388f296ffef7978f12bb33f3d9 Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Thu, 22 Oct 2020 02:07:59 +0530 Subject: [PATCH 090/346] Converted TEST into automic groups for reusable actions --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 ------------------- ...minCreateWidgetWthoutLayoutActionGroup.xml | 26 +++++++++++++ .../AdminWidgetAddLayoutUpdateActionGroup.xml | 18 +++++++++ ...minWidgetDeleteLayoutUpdateActionGroup.xml | 17 +++++++++ ...AddAndDeleteMultipleLayoutSectionsTest.xml | 11 +++++- .../View/Helper/SecureHtmlRenderer.php | 2 +- 6 files changed, 72 insertions(+), 40 deletions(-) delete mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml deleted file mode 100644 index b7ebd09c2fcc6..0000000000000 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<actionGroups - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup"> - <annotations> - <description>Goes to the Admin Widget creation page. Add and delete multiple layouts</description> - </annotations> - <arguments> - <argument name="widget"/> - </arguments> - <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> - <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> - <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> - <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> - <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> - <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> - <waitForAjaxLoad stepKey="waitForLoad"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate2"/> - <waitForAjaxLoad stepKey="waitForLoad2"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate3"/> - <waitForAjaxLoad stepKey="waitForLoad3"/> - <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionThird}}" stepKey="clickThirdDeleteButton"/> - <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionSecond}}" stepKey="clickSecondDeleteButton"/> - <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionFirst}}" stepKey="clickFirstDeleteButton"/> - <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml new file mode 100644 index 0000000000000..e9ee80c1a5f2a --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateWidgetWthoutLayoutActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateWidgetWthoutLayoutActionGroup"> + <annotations> + <description>Goes to the Admin Widget creation page without saving it</description> + </annotations> + <arguments> + <argument name="widget"/> + </arguments> + <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> + <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> + <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> + <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> + <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> + <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml new file mode 100644 index 0000000000000..fa73fa4926e10 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetAddLayoutUpdateActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminWidgetAddLayoutUpdateActionGroup"> + <annotations> + <description>Add layouts during widgets creation</description> + </annotations> + <waitForAjaxLoad stepKey="waitForLoad"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml new file mode 100644 index 0000000000000..e52fb1a7f6514 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminWidgetDeleteLayoutUpdateActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminWidgetDeleteLayoutUpdateActionGroup"> + <annotations> + <description>Delete layouts during widgets creation</description> + </annotations> + <click selector="{{AdminNewWidgetSection.deleteWidgetLayoutAction}}" stepKey="clickFirstDeleteButton"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml index 5a5652e1e9049..eee6058836f2e 100644 --- a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml @@ -29,8 +29,17 @@ <argument name="title" value="{{AdminMenuContentElementsWidgets.pageTitle}}"/> </actionGroup> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear1"/> - <actionGroup ref="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup" stepKey="addWidgetForTest"> + <actionGroup ref="AdminCreateWidgetWthoutLayoutActionGroup" stepKey="addWidgetForTest"> <argument name="widget" value="ProductsListWidget"/> </actionGroup> + <actionGroup ref="AdminWidgetAddLayoutUpdateActionGroup" stepKey="AddSecondLayout"/> + <actionGroup ref="AdminWidgetAddLayoutUpdateActionGroup" stepKey="AddThirdLayout"/> + <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteFirstLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteSecondLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> + <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteThirdLayoutForWidget"></actionGroup> + <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> </test> </tests> diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index ebc4b8870538f..87d4e88295356 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -112,7 +112,7 @@ function {$listenerFunction} () { {$attributeJavascript}; } var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); - if({$elementName}Array.lenght !== 'undefined'){ + if({$elementName}Array.length !== 'undefined'){ {$elementName}Array.forEach(function(element){ if (element) { element.{$eventName} = function (event) { From 0fee9a1ab949b29ae86fd4eca4150d4f6a10c895 Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Fri, 11 Sep 2020 11:01:41 +0530 Subject: [PATCH 091/346] Fixed issue when using dynamic elements --- .../Magento/Framework/View/Helper/SecureHtmlRenderer.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index 87d4e88295356..aedb2026e4bb5 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -116,6 +116,7 @@ function {$listenerFunction} () { {$elementName}Array.forEach(function(element){ if (element) { element.{$eventName} = function (event) { + event.preventDefault(); var targetElement = element; if (event && event.target) { targetElement = event.target; @@ -124,10 +125,8 @@ function {$listenerFunction} () { } } }); - } - -script; - + } + script; return $this->renderTag('script', ['type' => 'text/javascript'], $script, false); } From 20275ce6331957c854162c71742f7c9c7da25a50 Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Sat, 12 Sep 2020 20:06:59 +0530 Subject: [PATCH 092/346] Updated code for validate empty nodeList and covered MFTF --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 +++++++++++++++++++ ...AddAndDeleteMultipleLayoutSectionsTest.xml | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml new file mode 100644 index 0000000000000..b7ebd09c2fcc6 --- /dev/null +++ b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup"> + <annotations> + <description>Goes to the Admin Widget creation page. Add and delete multiple layouts</description> + </annotations> + <arguments> + <argument name="widget"/> + </arguments> + <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> + <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> + <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> + <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> + <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> + <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> + <waitForAjaxLoad stepKey="waitForLoad"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate2"/> + <waitForAjaxLoad stepKey="waitForLoad2"/> + <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate3"/> + <waitForAjaxLoad stepKey="waitForLoad3"/> + <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> + <click selector="{{AdminNewWidgetSection.deleteActionThird}}" stepKey="clickThirdDeleteButton"/> + <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> + <click selector="{{AdminNewWidgetSection.deleteActionSecond}}" stepKey="clickSecondDeleteButton"/> + <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> + <click selector="{{AdminNewWidgetSection.deleteActionFirst}}" stepKey="clickFirstDeleteButton"/> + <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml index eee6058836f2e..04c1552d53522 100644 --- a/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml +++ b/app/code/Magento/Widget/Test/Mftf/Test/AdminWidgetAddAndDeleteMultipleLayoutSectionsTest.xml @@ -42,4 +42,4 @@ <actionGroup ref="AdminWidgetDeleteLayoutUpdateActionGroup" stepKey="DeleteThirdLayoutForWidget"></actionGroup> <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> </test> -</tests> +</tests> \ No newline at end of file From a1f731f86f6fd3a5257ab042d952e48f5ace0440 Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Thu, 22 Oct 2020 02:07:59 +0530 Subject: [PATCH 093/346] Converted TEST into automic groups for reusable actions --- ...dDeleteMultipleLayoutWidgetActionGroup.xml | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml diff --git a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml b/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml deleted file mode 100644 index b7ebd09c2fcc6..0000000000000 --- a/app/code/Magento/Widget/Test/Mftf/ActionGroup/AdminCreateAndDeleteMultipleLayoutWidgetActionGroup.xml +++ /dev/null @@ -1,38 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<actionGroups - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminCreateAndDeleteMultipleLayoutWidgetActionGroup"> - <annotations> - <description>Goes to the Admin Widget creation page. Add and delete multiple layouts</description> - </annotations> - <arguments> - <argument name="widget"/> - </arguments> - <amOnPage url="{{AdminNewWidgetPage.url}}" stepKey="amOnAdminNewWidgetPage"/> - <selectOption selector="{{AdminNewWidgetSection.widgetType}}" userInput="{{widget.type}}" stepKey="setWidgetType"/> - <selectOption selector="{{AdminNewWidgetSection.widgetDesignTheme}}" userInput="{{widget.design_theme}}" stepKey="setWidgetDesignTheme"/> - <click selector="{{AdminNewWidgetSection.continue}}" stepKey="clickContinue"/> - <fillField selector="{{AdminNewWidgetSection.widgetTitle}}" userInput="{{widget.name}}" stepKey="fillTitle"/> - <selectOption selector="{{AdminNewWidgetSection.widgetStoreIds}}" userInput="{{widget.store_ids[0]}}" stepKey="setWidgetStoreIds"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate"/> - <waitForAjaxLoad stepKey="waitForLoad"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate2"/> - <waitForAjaxLoad stepKey="waitForLoad2"/> - <click selector="{{AdminNewWidgetSection.addLayoutUpdate}}" stepKey="clickAddLayoutUpdate3"/> - <waitForAjaxLoad stepKey="waitForLoad3"/> - <seeNumberOfElements userInput="3" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeThreeDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionThird}}" stepKey="clickThirdDeleteButton"/> - <seeNumberOfElements userInput="2" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeTwoDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionSecond}}" stepKey="clickSecondDeleteButton"/> - <seeNumberOfElements userInput="1" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeOneDeleteButtons"/> - <click selector="{{AdminNewWidgetSection.deleteActionFirst}}" stepKey="clickFirstDeleteButton"/> - <seeNumberOfElements userInput="0" selector="{{AdminNewWidgetSection.CountDeleteButtons}}" stepKey="seeZeroDeleteButtons"/> - </actionGroup> -</actionGroups> From 7d3d9c96f9dfbf7a828fc4874875d8f1436515e5 Mon Sep 17 00:00:00 2001 From: lykhachov <ilyalykhachov.com.ua> Date: Fri, 20 Nov 2020 12:10:20 +0200 Subject: [PATCH 094/346] replace changelog to changelogData --- .../Eav/Model/Mview/ChangeLogBatchWalker.php | 18 +++++++++--------- .../Magento/Test/Legacy/_files/words_ce.xml | 4 ---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php b/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php index fdc71faa90902..ff9268117d464 100644 --- a/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php +++ b/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php @@ -45,15 +45,15 @@ public function __construct( /** * Calculate EAV attributes size * - * @param ChangelogInterface $changelog + * @param ChangelogInterface $changelogData * @return int * @throws \Exception */ - private function calculateEavAttributeSize(ChangelogInterface $changelog): int + private function calculateEavAttributeSize(ChangelogInterface $changelogData): int { $connection = $this->resourceConnection->getConnection(); - if (!isset($this->entityTypeCodes[$changelog->getViewId()])) { + if (!isset($this->entityTypeCodes[$changelogData->getViewId()])) { throw new \Exception('Entity type for view was not defined'); } @@ -66,7 +66,7 @@ private function calculateEavAttributeSize(ChangelogInterface $changelog): int ['type' => $connection->getTableName('eav_entity_type')], 'type.entity_type_id=eav_attribute.entity_type_id' ) - ->where('type.entity_type_code = ?', $this->entityTypeCodes[$changelog->getViewId()]); + ->where('type.entity_type_code = ?', $this->entityTypeCodes[$changelogData->getViewId()]); return (int) $connection->fetchOne($select); } @@ -92,10 +92,10 @@ private function setGroupConcatMax(int $numberOfAttributes): void * @inheritdoc * @throws \Exception */ - public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toVersion, int $batchSize) + public function walk(ChangelogInterface $changelogData, int $fromVersionId, int $toVersion, int $batchSize) { $connection = $this->resourceConnection->getConnection(); - $numberOfAttributes = $this->calculateEavAttributeSize($changelog); + $numberOfAttributes = $this->calculateEavAttributeSize($changelogData); $this->setGroupConcatMax($numberOfAttributes); $select = $connection->select()->distinct(true) ->where( @@ -106,15 +106,15 @@ public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toV 'version_id <= ?', $toVersion ) - ->group([$changelog->getColumnName(), 'store_id']) + ->group([$changelogData->getColumnName(), 'store_id']) ->limit($batchSize); $columns = [ - $changelog->getColumnName(), + $changelogData->getColumnName(), 'attribute_ids' => new Expression('GROUP_CONCAT(attribute_id)'), 'store_id' ]; - $select->from($changelog->getName(), $columns); + $select->from($changelogData->getName(), $columns); return $connection->fetchAll($select); } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml index ccad52fae453e..92e7b15efed29 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/words_ce.xml @@ -73,9 +73,5 @@ <path>app/design/adminhtml/Magento/backend/Magento_Rma/web/css/source/_module.less</path> <word>rma</word> </item> - <item> - <path>app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php</path> - <word>changelog</word> - </item> </whitelist> </config> From 80a192467d74c1291d8a1da00a34d0fdb6090a77 Mon Sep 17 00:00:00 2001 From: lykhachov <ilyalykhachov.com.ua> Date: Fri, 20 Nov 2020 14:28:09 +0200 Subject: [PATCH 095/346] put "changelog" back --- .../Eav/Model/Mview/ChangeLogBatchWalker.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php b/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php index ff9268117d464..fdc71faa90902 100644 --- a/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php +++ b/app/code/Magento/Eav/Model/Mview/ChangeLogBatchWalker.php @@ -45,15 +45,15 @@ public function __construct( /** * Calculate EAV attributes size * - * @param ChangelogInterface $changelogData + * @param ChangelogInterface $changelog * @return int * @throws \Exception */ - private function calculateEavAttributeSize(ChangelogInterface $changelogData): int + private function calculateEavAttributeSize(ChangelogInterface $changelog): int { $connection = $this->resourceConnection->getConnection(); - if (!isset($this->entityTypeCodes[$changelogData->getViewId()])) { + if (!isset($this->entityTypeCodes[$changelog->getViewId()])) { throw new \Exception('Entity type for view was not defined'); } @@ -66,7 +66,7 @@ private function calculateEavAttributeSize(ChangelogInterface $changelogData): i ['type' => $connection->getTableName('eav_entity_type')], 'type.entity_type_id=eav_attribute.entity_type_id' ) - ->where('type.entity_type_code = ?', $this->entityTypeCodes[$changelogData->getViewId()]); + ->where('type.entity_type_code = ?', $this->entityTypeCodes[$changelog->getViewId()]); return (int) $connection->fetchOne($select); } @@ -92,10 +92,10 @@ private function setGroupConcatMax(int $numberOfAttributes): void * @inheritdoc * @throws \Exception */ - public function walk(ChangelogInterface $changelogData, int $fromVersionId, int $toVersion, int $batchSize) + public function walk(ChangelogInterface $changelog, int $fromVersionId, int $toVersion, int $batchSize) { $connection = $this->resourceConnection->getConnection(); - $numberOfAttributes = $this->calculateEavAttributeSize($changelogData); + $numberOfAttributes = $this->calculateEavAttributeSize($changelog); $this->setGroupConcatMax($numberOfAttributes); $select = $connection->select()->distinct(true) ->where( @@ -106,15 +106,15 @@ public function walk(ChangelogInterface $changelogData, int $fromVersionId, int 'version_id <= ?', $toVersion ) - ->group([$changelogData->getColumnName(), 'store_id']) + ->group([$changelog->getColumnName(), 'store_id']) ->limit($batchSize); $columns = [ - $changelogData->getColumnName(), + $changelog->getColumnName(), 'attribute_ids' => new Expression('GROUP_CONCAT(attribute_id)'), 'store_id' ]; - $select->from($changelogData->getName(), $columns); + $select->from($changelog->getName(), $columns); return $connection->fetchAll($select); } } From 906441de5d9237919192cf54556059a7ad167204 Mon Sep 17 00:00:00 2001 From: lykhachov <ilyalykhachov.com.ua> Date: Fri, 20 Nov 2020 15:51:11 +0200 Subject: [PATCH 096/346] added AdditionalColumnProcessorFactory class to unit tests --- .../Mview/Test/Unit/View/ChangelogTest.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php index 4af3f65be6883..16fc3a91924b8 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/View/ChangelogTest.php @@ -12,6 +12,7 @@ use Magento\Framework\DB\Ddl\Table; use Magento\Framework\DB\Select; use Magento\Framework\Mview\Config; +use Magento\Framework\Mview\View\AdditionalColumnsProcessor\ProcessorFactory; use Magento\Framework\Mview\View\Changelog; use Magento\Framework\Mview\View\ChangelogInterface; use PHPUnit\Framework\MockObject\MockObject; @@ -41,13 +42,19 @@ class ChangelogTest extends TestCase */ protected $resourceMock; + /** + * @var ProcessorFactory|MockObject + */ + protected $processorFactory; + protected function setUp(): void { $this->connectionMock = $this->createMock(Mysql::class); $this->resourceMock = $this->createMock(ResourceConnection::class); $this->mockGetConnection($this->connectionMock); + $this->processorFactory = $this->createMock(ProcessorFactory::class); - $this->model = new Changelog($this->resourceMock, $this->getMviewConfigMock()); + $this->model = new Changelog($this->resourceMock, $this->getMviewConfigMock(), $this->processorFactory); } /** @@ -69,7 +76,7 @@ public function testInstanceOf() $resourceMock = $this->createMock(ResourceConnection::class); $resourceMock->expects($this->once())->method('getConnection')->willReturn(true); - $model = new Changelog($resourceMock, $this->getMviewConfigMock()); + $model = new Changelog($resourceMock, $this->getMviewConfigMock(), $this->processorFactory); $this->assertInstanceOf(ChangelogInterface::class, $model); } @@ -80,7 +87,7 @@ public function testCheckConnectionException() $resourceMock = $this->createMock(ResourceConnection::class); $resourceMock->expects($this->once())->method('getConnection')->willReturn(null); - $model = new Changelog($resourceMock, $this->getMviewConfigMock()); + $model = new Changelog($resourceMock, $this->getMviewConfigMock(), $this->processorFactory); $model->setViewId('ViewIdTest'); $this->assertNull($model); } From e5b24273467e80dc0994cb7d5c9ae79c64d3ae3a Mon Sep 17 00:00:00 2001 From: lykhachov <ilyalykhachov.com.ua> Date: Fri, 20 Nov 2020 17:08:11 +0200 Subject: [PATCH 097/346] changes to Unit Tests --- .../Magento/Framework/Mview/Test/Unit/_files/mview_config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php index 36e7dca899047..af488ecf5589e 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/_files/mview_config.php @@ -32,7 +32,7 @@ 'processor' => \Magento\Framework\Mview\View\AdditionalColumnsProcessor\DefaultProcessor::class ], ], - 'iterator' => \Magento\Framework\Mview\View\ChangeLogBatchIterator::class + 'walker' => \Magento\Framework\Mview\View\ChangeLogBatchWalker::class ], ] ]; From ed41a6200b3517b49e9b64d5c44dc096294796bc Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Fri, 20 Nov 2020 12:25:59 -0600 Subject: [PATCH 098/346] MC-38787: Admin Product Grid Page indicator issue --- .../Magento/Ui/view/base/web/js/grid/search/search.js | 2 +- .../code/Magento/Ui/base/js/grid/search/search.test.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/grid/search/search.js b/app/code/Magento/Ui/view/base/web/js/grid/search/search.js index 307f3606a2e3f..d4db0100db7c6 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/search/search.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/search/search.js @@ -127,7 +127,7 @@ define([ apply: function (value) { value = value || this.inputValue; - this.keywordUpdated = this.value !== this.inputValue; + this.keywordUpdated = this.value !== value; this.value = this.inputValue = value.trim(); return this; diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js index 11af4cdc219a9..87fb61873b653 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/grid/search/search.test.js @@ -37,5 +37,15 @@ define([ searchObj.updatePreview(); expect(searchObj.updatePreview).toHaveBeenCalled(); }); + it('set the proper keywordUpdated value on new search keyword', function () { + searchObj.value = 'keyword 1'; + expect(searchObj.keywordUpdated).toEqual(false); + searchObj.apply('keyword 2'); + expect(searchObj.keywordUpdated).toEqual(true); + searchObj.apply('keyword 2'); + expect(searchObj.keywordUpdated).toEqual(false); + searchObj.apply('keyword 3'); + expect(searchObj.keywordUpdated).toEqual(true); + }); }); }); From 72d4cd76ada26777ae3733d46c3e46d1ec482cac Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Fri, 20 Nov 2020 16:27:41 -0600 Subject: [PATCH 099/346] MC-38787: Admin Product Grid Page indicator issue --- ...hProductGridByStringNoClearActionGroup.xml | 23 +++++ ...dPageNumberSetsToOneAfterNewSearchTest.xml | 95 +++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml new file mode 100644 index 0000000000000..a763f37ed153f --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="SearchProductGridByStringNoClearActionGroup"> + <annotations> + <description>Searches the Admin Products grid by string without clearing filters.</description> + </annotations> + <arguments> + <argument name="keyword" type="string"/> + </arguments> + + <fillField selector="{{AdminProductGridFilterSection.keywordSearch}}" userInput="{{keyword}}" stepKey="fillKeywordSearchField"/> + <click selector="{{AdminProductGridFilterSection.keywordSearchButton}}" stepKey="clickKeywordSearch"/> + <waitForPageLoad stepKey="waitForProductSearch"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml new file mode 100644 index 0000000000000..f2dd87e74e9de --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminGridPageNumberSetsToOneAfterNewSearchTest"> + + <annotations> + <features value="Catalog"/> + <stories value="Catalog grid"/> + <title value="Checking Catalog grid page number after entering a new search keyword"/> + <description value="Checking Catalog grid page number after entering a new search keyword"/> + <severity value="MINOR"/> + <testCaseId value="MC-xxxxx"/> + <useCaseId value="MC-38787"/> + <group value="Catalog"/> + </annotations> + + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <comment userInput="Clear product grid" stepKey="commentClearProductGrid"/> + <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="goToProductCatalog"/> + <actionGroup ref="ResetProductGridToDefaultViewActionGroup" stepKey="resetProductGridToDefaultView"/> + <actionGroup ref="DeleteProductsIfTheyExistActionGroup" stepKey="deleteProductIfTheyExist"/> + <createData stepKey="category1" entity="SimpleSubCategory"/> + + <createData stepKey="simpleProduct1" entity="SimpleProduct"> + <requiredEntity createDataKey="category1"/> + </createData> + <createData stepKey="simpleProduct2" entity="SimpleProduct"> + <requiredEntity createDataKey="category1"/> + </createData> + <createData stepKey="simpleProduct3" entity="SimpleProduct"> + <requiredEntity createDataKey="category1"/> + </createData> + <createData stepKey="simpleProduct4" entity="SimpleProduct"> + <requiredEntity createDataKey="category1"/> + </createData> + <createData stepKey="virtualProduct1" entity="VirtualProduct"> + <requiredEntity createDataKey="category1"/> + </createData> + <createData stepKey="virtualProduct2" entity="VirtualProduct"> + <requiredEntity createDataKey="category1"/> + </createData> + <createData stepKey="virtualProduct3" entity="VirtualProduct"> + <requiredEntity createDataKey="category1"/> + </createData> + </before> + + <after> + <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="goToProductCatalog"/> + <actionGroup ref="AdminDataGridDeleteCustomPerPageActionGroup" stepKey="deleteCustomAddedPerPage"> + <argument name="perPage" value="ProductPerPage.productCount"/> + </actionGroup> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="clearFilters"/> + + <deleteData stepKey="deleteCategory1" createDataKey="category1"/> + + <deleteData stepKey="deleteSimpleProduct1" createDataKey="simpleProduct1"/> + <deleteData stepKey="deleteSimpleProduct2" createDataKey="simpleProduct2"/> + <deleteData stepKey="deleteSimpleProduct3" createDataKey="simpleProduct3"/> + <deleteData stepKey="deleteSimpleProduct4" createDataKey="simpleProduct4"/> + <deleteData stepKey="deleteVirtualProduct1" createDataKey="virtualProduct1"/> + <deleteData stepKey="deleteVirtualProduct2" createDataKey="virtualProduct2"/> + <deleteData stepKey="deleteVirtualProduct3" createDataKey="virtualProduct3"/> + + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="goToProductCatalog"/> + + <actionGroup ref="AdminDataGridSelectCustomPerPageActionGroup" stepKey="select1ProductPerPage"> + <argument name="perPage" value="ProductPerPage.productCount"/> + </actionGroup> + + <actionGroup ref="SearchProductGridByStringNoClearActionGroup" stepKey="searchForSimpleProduct"> + <argument name="keyword" value="SimpleProduct"/> + </actionGroup> + + <comment userInput="Go to the next page" stepKey="nextPage"/> + <click selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="clickNextPageProductGrid"/> + <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="2" stepKey="seeOnSecondPageProductGrid"/> + + <actionGroup ref="SearchProductGridByStringNoClearActionGroup" stepKey="searchForVirtualProduct"> + <argument name="keyword" value="VirtualProduct"/> + </actionGroup> + + <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="1" stepKey="seeOnFirstPageProductGrid"/> + </test> +</tests> From fd8749f6ecea40dcd759b1bf76cb68695737fadf Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Fri, 20 Nov 2020 18:19:06 -0600 Subject: [PATCH 100/346] MC-38770: Exception during initialization is cacheable - fixed --- lib/internal/Magento/Framework/App/Bootstrap.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/internal/Magento/Framework/App/Bootstrap.php b/lib/internal/Magento/Framework/App/Bootstrap.php index 93d5535d0e10e..92b925836b295 100644 --- a/lib/internal/Magento/Framework/App/Bootstrap.php +++ b/lib/internal/Magento/Framework/App/Bootstrap.php @@ -386,7 +386,7 @@ private function initErrorHandler() $handler = new ErrorHandler(); set_error_handler([$handler, 'handler']); } - + /** * Getter for error code * @@ -428,9 +428,13 @@ public function isDeveloperMode() */ protected function terminate(\Throwable $e) { - + /** @var \Magento\Framework\HTTP\PhpEnvironment\Response $response */ + $response = $this->objectManager->get(\Magento\Framework\HTTP\PhpEnvironment\Response::class); + $response->clearHeaders(); + $response->setHttpResponseCode(500); + $response->setHeader('Content-Type', 'text/plain'); if ($this->isDeveloperMode()) { - echo $e; + $response->setBody($e); } else { $message = "An error has happened during application run. See exception log for details.\n"; try { @@ -441,8 +445,9 @@ protected function terminate(\Throwable $e) } catch (\Exception $e) { $message .= "Could not write error message to log. Please use developer mode to see the message.\n"; } - echo $message; + $response->setBody($message); } + $response->sendResponse(); exit(1); } // phpcs:enable From 876e37b6c907e542ecab093b5f67ca02c201d5cc Mon Sep 17 00:00:00 2001 From: Nikola Lardev <nikolalardev@gmail.com> Date: Sat, 21 Nov 2020 22:05:38 +0200 Subject: [PATCH 101/346] #30959 Add one more region for Greece and fix two Portugal states numbers --- .../Magento/Directory/Setup/Patch/Data/AddDataForGreece.php | 1 + .../Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php index a756035f1af4e..122a2b2bbc195 100644 --- a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php @@ -77,6 +77,7 @@ private function getDataForGreece() ['GR', 'GR-H', 'Stereá Elláda'], ['GR', 'GR-E', 'Thessalía'], ['GR', 'GR-K', 'Vóreio Aigaío'], + ['GR', 'GR-69', 'Ágion Óros'] ]; } diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php index 9daeb1cf5bf1e..2960d431f123a 100644 --- a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForPortugal.php @@ -82,8 +82,8 @@ private function getDataForPortugal() ['PT', 'PT-16', 'Viana do Castelo'], ['PT', 'PT-17', 'Vila Real'], ['PT', 'PT-18', 'Viseu'], - ['PT', 'PT-19', 'Região Autónoma dos Açores'], - ['PT', 'PT-20', 'Região Autónoma da Madeira'] + ['PT', 'PT-20', 'Região Autónoma dos Açores'], + ['PT', 'PT-30', 'Região Autónoma da Madeira'] ]; } From 98c0b0bb8bdec475109fcd822fd27d86c689bbd6 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Sun, 22 Nov 2020 12:37:08 +0200 Subject: [PATCH 102/346] adjusted comments to clarify that they were added for preserving backward compatibility --- .../Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml | 2 +- .../Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml | 2 +- .../Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml | 2 +- .../Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml | 2 +- .../AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml | 2 +- .../Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml index 4379fc283510d..afede97556513 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml @@ -61,7 +61,7 @@ <click selector="{{AdminOrderFormItemsSection.updateItemsAndQuantities}}" stepKey="clickUpdateItemsAndQuantitiesButton"/> <!--Fill customer group and customer email--> - <comment userInput="Fill Account Information" stepKey="selectCustomerGroup"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectCustomerGroup"/> <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail"> <argument name="email" value="{{Simple_US_Customer.email}}"/> </actionGroup> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml index 2d8b8e9b8fb46..6b714e0d18726 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithMinimumAmountEnabledTest.xml @@ -45,7 +45,7 @@ </actionGroup> <!--Fill customer group information--> - <comment userInput="Fill Account Information" stepKey="selectGroup"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectGroup"/> <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillEmail"> <argument name="email" value="{{Simple_US_Customer.email}}"/> </actionGroup> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml index 1e09f308018d2..addf978235af4 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderPaymentMethodValidationTest.xml @@ -48,7 +48,7 @@ <scrollToTopOfPage stepKey="scrollToTopOfOrderFormPage" after="seePaymentMethodRequired"/> <!--Fill customer group and customer email--> - <comment userInput="Fill Account Information" stepKey="selectCustomerGroup" after="scrollToTopOfOrderFormPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectCustomerGroup" after="scrollToTopOfOrderFormPage"/> <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail" after="selectCustomerGroup"> <argument name="email" value="{{Simple_US_Customer.email}}"/> </actionGroup> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml index 215c888833885..7c2309eeb7be3 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutEmailTest.xml @@ -46,7 +46,7 @@ </actionGroup> <!--Fill customer group and customer email--> - <comment userInput="Fill Account Information" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail" after="selectCustomerGroup"> <argument name="email" value="{{Simple_US_Customer.email}}"/> </actionGroup> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml index 48ce356a43174..db779a7340b07 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSubmitsOrderWithAndWithoutFieldsValidationTest.xml @@ -45,7 +45,7 @@ </actionGroup> <!--Fill customer group and customer email--> - <comment userInput="Fill Account Information" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectCustomerGroup" after="addSimpleProductToOrder"/> <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail" after="selectCustomerGroup"> <argument name="email" value="{{Simple_US_Customer.email}}"/> </actionGroup> diff --git a/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml b/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml index 61482d7f5a567..8bacc134c7ab8 100644 --- a/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml +++ b/app/code/Magento/Tax/Test/Mftf/Test/AdminCheckingTaxReportGridTest.xml @@ -154,7 +154,7 @@ </actionGroup> <!--Fill customer group and customer email--> - <comment userInput="Fill Account Information" stepKey="selectCustomerGroup"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectCustomerGroup"/> <actionGroup ref="AdminFillAccountInformationOnCreateOrderPageActionGroup" stepKey="fillCustomerEmail"> <argument name="email" value="{{Simple_US_Customer.email}}"/> </actionGroup> From 84e6e1e0d9cf8b3faa983627a37f7643aa135134 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 23 Nov 2020 16:33:47 +0200 Subject: [PATCH 103/346] refactored AdminCreateOrderAddProductCheckboxTest --- ...ductToOrderAndCheckCheckboxActionGroup.xml | 19 +++++++++++++++++++ ...AdminCreateOrderAddProductCheckboxTest.xml | 19 +++++++++++-------- 2 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml new file mode 100644 index 0000000000000..8aa50526519b8 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AddSimpleProductToOrderAndCheckCheckboxActionGroup" extends="AddSimpleProductToOrderActionGroup"> + <annotations> + <description>Adds the provided Simple Product to an Order. Checks of checkbox is checkedFills in the provided Product Qty. Clicks on 'Add Selected Product(s) to Order'.</description> + </annotations> + + <seeCheckboxIsChecked selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="verifyProductChecked" after="selectProduct"/> + + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml index baef605ad52af..718464f215fcb 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml @@ -34,17 +34,20 @@ <argument name="customer" value="$$createSimpleCustomer$$"/> </actionGroup> - <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> - <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="$$createSimpleProduct.sku$$" stepKey="fillSkuFilterBundle"/> - <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearchBundle"/> - <scrollTo selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" x="0" y="-100" stepKey="scrollToCheckColumn"/> - <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> - <seeCheckboxIsChecked selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="verifyProductChecked"/> - + <actionGroup ref="AddSimpleProductToOrderAndCheckCheckboxActionGroup" stepKey="clickAddProducts"> + <argument name="product" value="$createSimpleProduct$"/> + </actionGroup> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="fillSkuFilterBundle"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickSearchBundle"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="scrollToCheckColumn"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectProduct"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="verifyProductChecked"/> + <after> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> <deleteData createDataKey="createSimpleCustomer" stepKey="deleteSimpleCustomer"/> </after> </test> -</tests> +</tests> \ No newline at end of file From 3838099a2a35e4087365db405c3d8ce75d7c3b49 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 23 Nov 2020 16:42:51 +0200 Subject: [PATCH 104/346] refactored --- .../AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml index 8aa50526519b8..b26a592d3442a 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml @@ -10,7 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AddSimpleProductToOrderAndCheckCheckboxActionGroup" extends="AddSimpleProductToOrderActionGroup"> <annotations> - <description>Adds the provided Simple Product to an Order. Checks of checkbox is checkedFills in the provided Product Qty. Clicks on 'Add Selected Product(s) to Order'.</description> + <description>Adds the provided Simple Product to an Order. Checks if checkbox is checked. Fills in the provided Product Qty. Clicks on 'Add Selected Product(s) to Order'.</description> </annotations> <seeCheckboxIsChecked selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="verifyProductChecked" after="selectProduct"/> From 60460f6c4963e18ca8a7a8e36bb51b14ce71fe2b Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 23 Nov 2020 21:18:57 +0200 Subject: [PATCH 105/346] refactored --- .../AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml index b26a592d3442a..67b10d6955775 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AddSimpleProductToOrderAndCheckCheckboxActionGroup.xml @@ -8,7 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AddSimpleProductToOrderAndCheckCheckboxActionGroup" extends="AddSimpleProductToOrderActionGroup"> + <actionGroup name="AdminAddSimpleProductToOrderAndCheckCheckboxActionGroup" extends="AddSimpleProductToOrderActionGroup"> <annotations> <description>Adds the provided Simple Product to an Order. Checks if checkbox is checked. Fills in the provided Product Qty. Clicks on 'Add Selected Product(s) to Order'.</description> </annotations> From b61c19ee94bbe294f6d42f807cedd9d26c715450 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 23 Nov 2020 21:19:57 +0200 Subject: [PATCH 106/346] refactored --- .../Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml index 718464f215fcb..13b91fa605bca 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderAddProductCheckboxTest.xml @@ -34,7 +34,7 @@ <argument name="customer" value="$$createSimpleCustomer$$"/> </actionGroup> - <actionGroup ref="AddSimpleProductToOrderAndCheckCheckboxActionGroup" stepKey="clickAddProducts"> + <actionGroup ref="AdminAddSimpleProductToOrderAndCheckCheckboxActionGroup" stepKey="clickAddProducts"> <argument name="product" value="$createSimpleProduct$"/> </actionGroup> From ba1a3393e5b09a141a2a06e11d15dad91a8e041c Mon Sep 17 00:00:00 2001 From: Evangelos Pallis <info.vpsnak@gmail.com> Date: Mon, 23 Nov 2020 22:17:20 +0200 Subject: [PATCH 107/346] Fix wrong format error DHL shipping label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix "The response is in wrong format." error while generating dhl shipping label. When product name has unicode characters substr() is sending � in <PieceContents> causing erros dhl syntax errors. --- app/code/Magento/Dhl/Model/Carrier.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Dhl/Model/Carrier.php b/app/code/Magento/Dhl/Model/Carrier.php index c5eb27b21e58b..ac82120893698 100644 --- a/app/code/Magento/Dhl/Model/Carrier.php +++ b/app/code/Magento/Dhl/Model/Carrier.php @@ -1748,7 +1748,7 @@ protected function _shipmentDetails($xml, $rawRequest, $originRegion = '') foreach ($package['items'] as $item) { $content[] = $item['name']; } - $nodePiece->addChild('PieceContents', substr(implode(',', $content), 0, 34)); + $nodePiece->addChild('PieceContents', $this->string->substr(implode(',', $content), 0, 34)); } $nodeShipmentDetails->addChild('Weight', sprintf('%.3f', $rawRequest->getPackageWeight())); From fc4481c60a770a548814e60aae1d493a8ef93384 Mon Sep 17 00:00:00 2001 From: Sergiy Vasiutynskyi <s.vasiutynskyi@atwix.com> Date: Tue, 24 Nov 2020 11:08:13 +0200 Subject: [PATCH 108/346] Removed 'indexer:reindex', 'cache:flush' commands and usage of AdminReindexAndFlushCache action group from tests --- ...tBundlePlaceOrderWithVirtualAndSimpleChildrenTest.xml | 3 +-- ...CheckNoAppearDefaultOptionConfigurableProductTest.xml | 2 +- .../AdminCreateCatalogPriceRuleForCustomerGroupTest.xml | 3 +-- ...onfigurableProductWithAssignedSimpleProducts2Test.xml | 2 +- ...CatalogRuleForConfigurableProductWithOptions2Test.xml | 2 +- ...heckboxIsDisabledCreatePermanentRedirectSetNoTest.xml | 4 ++-- ...ountDownloadableProductLinkAfterPartialRefundTest.xml | 9 ++++----- .../ActionGroup/AdminReindexAndFlushCacheActionGroup.xml | 9 +++++++++ ...ontPaypalSmartButtonWithFranceMerchantCountryTest.xml | 2 +- .../Test/Mftf/Test/StorefrontReorderAsGuestTest.xml | 5 ++--- 10 files changed, 23 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundlePlaceOrderWithVirtualAndSimpleChildrenTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundlePlaceOrderWithVirtualAndSimpleChildrenTest.xml index fe4faed29d144..8b19753067593 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundlePlaceOrderWithVirtualAndSimpleChildrenTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontBundlePlaceOrderWithVirtualAndSimpleChildrenTest.xml @@ -48,8 +48,7 @@ <argument name="productId" value="$createFixedBundleProduct.id$"/> </actionGroup> <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct"/> - <!--Perform reindex and flush cache--> - <actionGroup ref="AdminReindexAndFlushCache" stepKey="reindexAndFlushCache"/> + <comment userInput="Adding the comment to replace AdminReindexAndFlushCache action group ('indexer:reindex', 'cache:flush' commands) for preserving Backward Compatibility" stepKey="reindexAndFlushCache"/> </before> <after> <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProductForBundleItem"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckNoAppearDefaultOptionConfigurableProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckNoAppearDefaultOptionConfigurableProductTest.xml index 507e4ae14e83c..2f38e16a44476 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckNoAppearDefaultOptionConfigurableProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckNoAppearDefaultOptionConfigurableProductTest.xml @@ -44,7 +44,7 @@ </actionGroup> <actionGroup ref="AdminSetQuantityToEachSkusConfigurableProductActionGroup" stepKey="saveConfigurable"/> <grabValueFrom selector="{{NewProductPageSection.sku}}" stepKey="grabSkuProduct"/> - <magentoCLI command="indexer:reindex" stepKey="reindex"/> + <comment userInput="Adding the comment to replace 'indexer:reindex' command for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="SelectStorefrontSideBarAttributeOption" stepKey="expandOption"> <argument name="categoryName" value="$$createCategory.name$$"/> diff --git a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest/AdminCreateCatalogPriceRuleForCustomerGroupTest.xml b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest/AdminCreateCatalogPriceRuleForCustomerGroupTest.xml index fb218297b646d..3c08fbdf641e4 100644 --- a/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest/AdminCreateCatalogPriceRuleForCustomerGroupTest.xml +++ b/app/code/Magento/CatalogRule/Test/Mftf/Test/AdminCreateCatalogPriceRuleTest/AdminCreateCatalogPriceRuleForCustomerGroupTest.xml @@ -27,8 +27,7 @@ <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="AdminCatalogPriceRuleDeleteAllActionGroup" stepKey="deleteAllCatalogPriceRule"/> - <!-- Perform reindex and flush cache --> - <actionGroup ref="AdminReindexAndFlushCache" stepKey="reindexAndFlushCache"/> + <comment userInput="Adding the comment to replace AdminReindexAndFlushCache action group ('indexer:reindex', 'cache:flush' commands) for preserving Backward Compatibility" stepKey="reindexAndFlushCache"/> </before> <after> diff --git a/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithAssignedSimpleProducts2Test.xml b/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithAssignedSimpleProducts2Test.xml index 48f53da8e2a2e..ca9017b7c5f29 100644 --- a/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithAssignedSimpleProducts2Test.xml +++ b/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithAssignedSimpleProducts2Test.xml @@ -190,7 +190,7 @@ </actionGroup> <actionGroup ref="AdminCatalogPriceRuleSaveAndApplyActionGroup" stepKey="saveAndApplyCatalogPriceRule"/> - <actionGroup ref="AdminReindexAndFlushCache" stepKey="reindexAndFlushCache"/> + <comment userInput="Adding the comment to replace AdminReindexAndFlushCache action group ('indexer:reindex', 'cache:flush' commands) for preserving Backward Compatibility" stepKey="reindexAndFlushCache"/> <!-- Login to storefront from customer --> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginCustomerOnStorefront"> diff --git a/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithOptions2Test.xml b/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithOptions2Test.xml index 350f896606c19..b20bd34106e03 100644 --- a/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithOptions2Test.xml +++ b/app/code/Magento/CatalogRuleConfigurable/Test/Mftf/Test/AdminApplyCatalogRuleForConfigurableProductWithOptions2Test.xml @@ -173,7 +173,7 @@ </actionGroup> <actionGroup ref="AdminCatalogPriceRuleSaveAndApplyActionGroup" stepKey="saveAndApplySecondPriceRule"/> - <actionGroup ref="AdminReindexAndFlushCache" stepKey="reindexAndFlushCache"/> + <comment userInput="Adding the comment to replace AdminReindexAndFlushCache action group ('indexer:reindex', 'cache:flush' commands) for preserving Backward Compatibility" stepKey="reindexAndFlushCache"/> <!-- Assert product in storefront product page --> <amOnPage url="{{StorefrontProductPage.url($$createConfigProduct.custom_attributes[url_key]$$)}}" stepKey="amOnProductPage"/> diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml index d529c6dd3ecc3..fc9eb8529da6f 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml +++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminVerifyCheckboxIsDisabledCreatePermanentRedirectSetNoTest.xml @@ -18,7 +18,7 @@ </annotations> <before> <magentoCLI command="config:set {{DisableCreatePermanentRedirect.path}} {{DisableCreatePermanentRedirect.value}}" stepKey="enableCreatePermanentRedirect"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> + <comment userInput="Adding the comment to replace 'cache:flush' command for preserving Backward Compatibility" stepKey="flushCache"/> <createData entity="_defaultCategory" stepKey="createDefaultCategory"/> <createData entity="SimpleProduct" stepKey="createSimpleProduct"> <requiredEntity createDataKey="createDefaultCategory"/> @@ -29,7 +29,7 @@ <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> <deleteData createDataKey="createDefaultCategory" stepKey="deleteDefaultCategory"/> <magentoCLI command="config:set {{EnableCreatePermanentRedirect.path}} {{EnableCreatePermanentRedirect.value}}" stepKey="disableCreatePermanentRedirect"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> + <comment userInput="Adding the comment to replace 'cache:flush' command for preserving Backward Compatibility" stepKey="flushCache"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPage"> diff --git a/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAccountDownloadableProductLinkAfterPartialRefundTest.xml b/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAccountDownloadableProductLinkAfterPartialRefundTest.xml index d82cc25b0eccf..dc48f600167a2 100644 --- a/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAccountDownloadableProductLinkAfterPartialRefundTest.xml +++ b/app/code/Magento/Downloadable/Test/Mftf/Test/StorefrontAccountDownloadableProductLinkAfterPartialRefundTest.xml @@ -30,9 +30,8 @@ <createData entity="downloadableLink1" stepKey="addDownloadableLink1"> <requiredEntity createDataKey="createDownloadableProduct"/> </createData> - - <magentoCLI command="indexer:reindex" stepKey="reindex"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> + <comment userInput="Adding the comment to replace 'indexer:reindex' command for preserving Backward Compatibility" stepKey="reindex"/> + <comment userInput="Adding the comment to replace 'cache:flush' command for preserving Backward Compatibility" stepKey="flushCache"/> <createData entity="Simple_US_Customer_Multiple_Addresses" stepKey="createCustomer"/> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="signIn"> @@ -51,8 +50,8 @@ <magentoCLI stepKey="removeDownloadableDomain" command="downloadable:domains:remove example.com static.magento.com"/> <magentoCLI command="config:set {{EnableFlatRateConfigData.path}} {{EnableFlatRateConfigData.value}}" stepKey="enableFlatRate"/> - <magentoCLI command="indexer:reindex" stepKey="reindex"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> + <comment userInput="Adding the comment to replace 'indexer:reindex' command for preserving Backward Compatibility" stepKey="reindex"/> + <comment userInput="Adding the comment to replace 'cache:flush' command for preserving Backward Compatibility" stepKey="flushCache"/> </after> <actionGroup ref="StorefrontAddSimpleProductToShoppingCartActionGroup" stepKey="addSimpleProductToCart"> diff --git a/app/code/Magento/Indexer/Test/Mftf/ActionGroup/AdminReindexAndFlushCacheActionGroup.xml b/app/code/Magento/Indexer/Test/Mftf/ActionGroup/AdminReindexAndFlushCacheActionGroup.xml index d474094dcd54b..e7e7ba82bf09c 100644 --- a/app/code/Magento/Indexer/Test/Mftf/ActionGroup/AdminReindexAndFlushCacheActionGroup.xml +++ b/app/code/Magento/Indexer/Test/Mftf/ActionGroup/AdminReindexAndFlushCacheActionGroup.xml @@ -9,6 +9,15 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminReindexAndFlushCache"> <annotations> + <!-- + PLEASE NOTE: + The action group runs commands to reindex ALL indexers and to flush ALL cache types. + It's better to specify needed index (for reindexing) / cache type (for cache flushing). + Please use the following action groups: + - CliIndexerReindexActionGroup - run reindex by CLI with specified indexers + - CliCacheCleanActionGroup - run cache:clean by CLI with specified cache tags + - CliCacheFlushActionGroup - run cache:flush by CLI with specified cache tags + --> <description>Run reindex and flush cache.</description> </annotations> diff --git a/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonWithFranceMerchantCountryTest.xml b/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonWithFranceMerchantCountryTest.xml index a4d99ecbf7e61..7e3c4dab4588e 100644 --- a/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonWithFranceMerchantCountryTest.xml +++ b/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonWithFranceMerchantCountryTest.xml @@ -29,7 +29,7 @@ <!--Enable Advanced Setting--> <magentoCLI command="config:set {{StorefrontPaypalEnableSkipOrderReviewStepConfigData.path}} {{StorefrontPaypalEnableSkipOrderReviewStepConfigData.value}}" stepKey="enableSkipOrderReview"/> <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShipping"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> + <comment userInput="Adding the comment to replace 'cache:flush' command for preserving Backward Compatibility" stepKey="flushCache"/> </before> <after> <magentoCLI command="config:set {{StorefrontPaypalDisableSkipOrderReviewStepConfigData.path}} {{StorefrontPaypalDisableSkipOrderReviewStepConfigData.value}}" stepKey="disableSkipOrderReview"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontReorderAsGuestTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontReorderAsGuestTest.xml index 0718783534925..2b60c1d7ba550 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontReorderAsGuestTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontReorderAsGuestTest.xml @@ -24,9 +24,8 @@ </createData> <!-- Create Customer Account --> <createData entity="Simple_US_Customer" stepKey="createCustomer"/> - <!-- Reindex and flush cache --> - <magentoCLI command="indexer:reindex" stepKey="reindex"/> - <magentoCLI command="cache:flush" stepKey="flushCache"/> + <comment userInput="Adding the comment to replace 'indexer:reindex' command for preserving Backward Compatibility" stepKey="reindex"/> + <comment userInput="Adding the comment to replace 'cache:flush' command for preserving Backward Compatibility" stepKey="flushCache"/> </before> <after> <deleteData createDataKey="createCustomer" stepKey="deleteCreateCustomer"/> From 719c206661d00fd526f43041b89d3ddd041154da Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Tue, 24 Nov 2020 11:05:16 -0600 Subject: [PATCH 109/346] MC-38787: Admin Product Grid Page indicator issue --- ...inGridPageNumberSetsToOneAfterNewSearchTest.xml | 14 ++++++++------ .../Section/AdminDataGridPaginationSection.xml | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml index f2dd87e74e9de..0cc57ba94dac6 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml @@ -13,10 +13,10 @@ <annotations> <features value="Catalog"/> <stories value="Catalog grid"/> - <title value="Checking Catalog grid page number after entering a new search keyword"/> - <description value="Checking Catalog grid page number after entering a new search keyword"/> - <severity value="MINOR"/> - <testCaseId value="MC-xxxxx"/> + <title value="Updating the search keyword in admin product grid should reset current page to the first one"/> + <description value="When changing the search keyword in admin product grid, new results should be displayed from the page one"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-39332"/> <useCaseId value="MC-38787"/> <group value="Catalog"/> </annotations> @@ -82,14 +82,16 @@ <argument name="keyword" value="SimpleProduct"/> </actionGroup> + <waitForElementVisible selector="{{AdminDataGridPaginationSection.totalPagesCount('4')}}" stepKey="seeTotalPagesIsFourOnFirstSearch"/> <comment userInput="Go to the next page" stepKey="nextPage"/> <click selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="clickNextPageProductGrid"/> - <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="2" stepKey="seeOnSecondPageProductGrid"/> + <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="2" stepKey="seeOnSecondPageProductGridOnFirstSearch"/> <actionGroup ref="SearchProductGridByStringNoClearActionGroup" stepKey="searchForVirtualProduct"> <argument name="keyword" value="VirtualProduct"/> </actionGroup> - <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="1" stepKey="seeOnFirstPageProductGrid"/> + <waitForElementVisible selector="{{AdminDataGridPaginationSection.totalPagesCount('3')}}" stepKey="seeTotalPagesIsThreeOnSecondSearch"/> + <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="1" stepKey="seeOnFirstPageProductGridOnSecondSearch"/> </test> </tests> diff --git a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml index 51cebdb01a74d..eaea88fdddb03 100644 --- a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml +++ b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridPaginationSection.xml @@ -20,6 +20,7 @@ <element name="previousPage" type="button" selector="div.admin__data-grid-pager > button.action-previous" timeout="30"/> <element name="currentPage" type="input" selector="div.admin__data-grid-pager > input[data-ui-id='current-page-input']"/> <element name="totalPages" type="text" selector="div.admin__data-grid-pager > label"/> + <element name="totalPagesCount" type="text" selector="//div[@class='admin__data-grid-pager']//label[@class='admin__control-support-text' and .='of {{arg1}}']" parameterized="true"/> <element name="perPageDropDownValue" type="input" selector=".selectmenu-value input" timeout="30"/> <element name="selectedPage" type="input" selector="#sales_order_create_search_grid_page-current" timeout="30"/> <element name="nextPageActive" type="button" selector="div.admin__data-grid-pager > button.action-next:not(.disabled)" timeout="30"/> From 92dc76438063e68f7523d5ab036a57d7faf7bc03 Mon Sep 17 00:00:00 2001 From: Jason Woods <devel@jasonwoods.me.uk> Date: Tue, 24 Nov 2020 17:26:00 +0000 Subject: [PATCH 110/346] Update app/code/Magento/Cron/Model/DeadlockRetrier.php Co-authored-by: Buba Suma <bubasuma@users.noreply.github.com> --- app/code/Magento/Cron/Model/DeadlockRetrier.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Cron/Model/DeadlockRetrier.php b/app/code/Magento/Cron/Model/DeadlockRetrier.php index 63f7453c8df3c..ab180e93e0ca3 100644 --- a/app/code/Magento/Cron/Model/DeadlockRetrier.php +++ b/app/code/Magento/Cron/Model/DeadlockRetrier.php @@ -44,7 +44,7 @@ public function execute(callable $callback, AdapterInterface $connection) try { return $callback(); } catch (DeadlockException $e) { - $this->logger->warning(sprintf("Deadlock detected in cron cleanup: %s", $e->getMessage())); + $this->logger->warning(sprintf("Deadlock detected in cron: %s", $e->getMessage())); continue; } } From 81d13022b4aa4b7d5c07e26be54e412563bb02d6 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Mon, 23 Nov 2020 10:55:25 -0600 Subject: [PATCH 111/346] MC-38951: Images positions are inconsistent across store-views if images were added in a store-view level - Fix images positions for default scope if image were added in store view level --- .../Product/Helper/Form/Gallery/Content.php | 11 +- .../Model/Product/Gallery/ReadHandler.php | 32 ++++- .../Helper/Form/Gallery/ContentTest.php | 130 ++++++++++++++++++ .../Block/Product/View/GalleryTest.php | 102 ++++++++++++++ 4 files changed, 270 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php index 57cea59bee207..b06edc43cd71d 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/Content.php @@ -209,7 +209,14 @@ public function getImagesJson() */ private function sortImagesByPosition($images) { - if (is_array($images)) { + $nullPositions = []; + foreach ($images as $index => $image) { + if ($image['position'] === null) { + $nullPositions[] = $image; + unset($images[$index]); + } + } + if (is_array($images) && !empty($images)) { usort( $images, function ($imageA, $imageB) { @@ -217,7 +224,7 @@ function ($imageA, $imageB) { } ); } - return $images; + return array_merge($images, $nullPositions); } /** diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php index a3726207b3024..ed2e09249e495 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/ReadHandler.php @@ -64,9 +64,9 @@ public function execute($entity, $arguments = []) $this->addMediaDataToProduct( $entity, - $mediaEntries + $this->sortMediaEntriesByPosition($mediaEntries) ); - + return $entity; } @@ -108,7 +108,7 @@ public function getAttribute() * Find default value * * @param string $key - * @param string[] &$image + * @param string[] $image * @return string * @deprecated 101.0.1 * @since 101.0.0 @@ -121,4 +121,30 @@ protected function findDefaultValue($key, &$image) return ''; } + + /** + * Sort media entries by position + * + * @param array $mediaEntries + * @return array + */ + private function sortMediaEntriesByPosition(array $mediaEntries): array + { + $mediaEntriesWithNullPositions = []; + foreach ($mediaEntries as $index => $mediaEntry) { + if ($mediaEntry['position'] === null) { + $mediaEntriesWithNullPositions[] = $mediaEntry; + unset($mediaEntries[$index]); + } + } + if (!empty($mediaEntries)) { + usort( + $mediaEntries, + function ($entryA, $entryB) { + return ($entryA['position'] < $entryB['position']) ? -1 : 1; + } + ); + } + return array_merge($mediaEntries, $mediaEntriesWithNullPositions); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php index 7e94484961f9e..28c5d435cd038 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php @@ -6,15 +6,20 @@ namespace Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Gallery; +use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Gallery; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Gallery\UpdateHandler; use Magento\Framework\App\Request\DataPersistorInterface; use Magento\Framework\Registry; +use Magento\Store\Api\StoreRepositoryInterface; +use Magento\Store\Model\Store; use Magento\TestFramework\Helper\Bootstrap; /** * @magentoAppArea adminhtml + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ContentTest extends \PHPUnit\Framework\TestCase { @@ -35,6 +40,16 @@ class ContentTest extends \PHPUnit\Framework\TestCase */ private $dataPersistor; + /** + * @var StoreRepositoryInterface + */ + private $storeRepository; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + /** * @inheritdoc */ @@ -51,6 +66,8 @@ protected function setUp(): void $this->block->setElement($gallery); $this->registry = Bootstrap::getObjectManager()->get(Registry::class); $this->dataPersistor = Bootstrap::getObjectManager()->get(DataPersistorInterface::class); + $this->storeRepository = Bootstrap::getObjectManager()->create(StoreRepositoryInterface::class); + $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); } public function testGetUploader() @@ -120,6 +137,119 @@ public function getImagesAndImageTypesDataProvider() ]; } + /** + * Tests images positions in store view + * + * @magentoDataFixture Magento/Catalog/_files/product_with_image.php + * @magentoDataFixture Magento/Store/_files/second_store.php + * @dataProvider imagesPositionStoreViewDataProvider + * @param string $addFromStore + * @param array $newImages + * @param string $viewFromStore + * @param array $expectedImages + * @return void + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testImagesPositionStoreView( + string $addFromStore, + array $newImages, + string $viewFromStore, + array $expectedImages + ): void { + $storeId = (int)$this->storeRepository->get($addFromStore)->getId(); + $product = $this->getProduct($storeId); + $images = $product->getData('media_gallery')['images']; + $images = array_merge($images, $newImages); + $product->setData('media_gallery', ['images' => $images]); + $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class); + $updateHandler->execute($product); + $storeId = (int)$this->storeRepository->get($viewFromStore)->getId(); + $product = $this->getProduct($storeId); + $this->registry->register('current_product', $product); + $actualImages = array_map( + function ($item) { + return [ + 'file' => $item['file'], + 'label' => $item['label'], + 'position' => $item['position'], + ]; + }, + json_decode($this->block->getImagesJson(), true) + ); + $this->assertEquals($expectedImages, array_values($actualImages)); + } + + /** + * @return array[] + */ + public function imagesPositionStoreViewDataProvider(): array + { + return [ + [ + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_small_image.jpg', + 'position' => 2, + 'label' => 'New Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ] + ], + 'default', + [ + [ + 'file' => '/m/a/magento_image.jpg', + 'label' => 'Image Alt Text', + 'position' => 1, + ], + [ + 'file' => '/m/a/magento_small_image.jpg', + 'label' => null, + 'position' => null, + ], + ] + ], + [ + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_small_image.jpg', + 'position' => 2, + 'label' => 'New Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ] + ], + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_image.jpg', + 'label' => 'Image Alt Text', + 'position' => 1, + ], + [ + 'file' => '/m/a/magento_small_image.jpg', + 'label' => 'New Image Alt Text', + 'position' => 2, + ], + ] + ] + ]; + } + + /** + * Returns product for testing. + * + * @param int $storeId + * @param string $sku + * @return ProductInterface + */ + private function getProduct(int $storeId = Store::DEFAULT_STORE_ID, string $sku = 'simple'): ProductInterface + { + return $this->productRepository->get($sku, false, $storeId, true); + } + /** * Prepare product, and set it to registry and data persistor. * diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php index b57969280cdf3..2941349a94eaa 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php @@ -9,6 +9,7 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Gallery\UpdateHandler; use Magento\Catalog\Model\ResourceModel\Product as ProductResource; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\View\LayoutInterface; @@ -392,6 +393,107 @@ public function galleryImagesOnStoreViewDataProvider(): array ]; } + /** + * Tests images positions in store view + * + * @magentoDataFixture Magento/Catalog/_files/product_with_image.php + * @magentoDataFixture Magento/Store/_files/second_store.php + * @magentoConfigFixture default/web/url/catalog_media_url_format image_optimization_parameters + * @dataProvider imagesPositionStoreViewDataProvider + * @param string $addFromStore + * @param array $newImages + * @param string $viewFromStore + * @param array $expectedImages + * @return void + */ + public function testImagesPositionStoreView( + string $addFromStore, + array $newImages, + string $viewFromStore, + array $expectedImages + ): void { + $storeId = (int)$this->storeRepository->get($addFromStore)->getId(); + $product = $this->getProduct($storeId); + $images = $product->getData('media_gallery')['images']; + $images = array_merge($images, $newImages); + $product->setData('media_gallery', ['images' => $images]); + $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class); + $updateHandler->execute($product); + $storeId = (int)$this->storeRepository->get($viewFromStore)->getId(); + $product = $this->getProduct($storeId); + $this->block->setData('product', $product); + $actualImages = array_map( + function ($item) { + return [ + 'img' => parse_url($item['img'], PHP_URL_PATH), + 'caption' => $item['caption'], + 'position' => $item['position'], + ]; + }, + $this->serializer->unserialize($this->block->getGalleryImagesJson()) + ); + $this->assertEquals($expectedImages, array_values($actualImages)); + } + + /** + * @return array[] + */ + public function imagesPositionStoreViewDataProvider(): array + { + return [ + [ + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_small_image.jpg', + 'position' => 2, + 'label' => 'New Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ] + ], + 'default', + [ + [ + 'img' => '/media/catalog/product/m/a/magento_image.jpg', + 'caption' => 'Image Alt Text', + 'position' => 1, + ], + [ + 'img' => '/media/catalog/product/m/a/magento_small_image.jpg', + 'caption' => 'Simple Product', + 'position' => null, + ], + ] + ], + [ + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_small_image.jpg', + 'position' => 2, + 'label' => 'New Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ] + ], + 'fixture_second_store', + [ + [ + 'img' => '/media/catalog/product/m/a/magento_image.jpg', + 'caption' => 'Image Alt Text', + 'position' => 1, + ], + [ + 'img' => '/media/catalog/product/m/a/magento_small_image.jpg', + 'caption' => 'New Image Alt Text', + 'position' => 2, + ], + ] + ] + ]; + } + /** * Updates product gallery images and saves product. * From be7872aa9374e45ac089d732c93f50df9faaa373 Mon Sep 17 00:00:00 2001 From: Oleh Usik <o.usik@atwix.com> Date: Wed, 25 Nov 2020 13:10:29 +0200 Subject: [PATCH 112/346] remove clearing cache for integration tests --- .../testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php | 3 +-- .../Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php | 2 -- .../Magento/Catalog/Controller/Adminhtml/ProductTest.php | 3 --- .../testsuite/Magento/Catalog/Model/ConfigTest.php | 3 --- .../Product/Attribute/Source/CountryofmanufactureTest.php | 1 - .../Model/ResourceModel/Attribute/Entity/AttributeTest.php | 1 - .../DataProvider/Product/Form/Modifier/CategoriesTest.php | 1 - .../Magento/Customer/Model/AddressMetadataTest.php | 1 - .../Magento/Customer/Model/CustomerMetadataTest.php | 1 - .../testsuite/Magento/Directory/Block/DataTest.php | 2 -- .../integration/testsuite/Magento/Eav/Model/ConfigTest.php | 6 ------ .../Model/Entity/Attribute/Frontend/DefaultFrontendTest.php | 1 - .../Magento/Eav/Model/Entity/AttributeLoaderTest.php | 1 - .../testsuite/Magento/Framework/App/Config/InitialTest.php | 2 -- .../Framework/App/ObjectManager/ConfigLoaderTest.php | 1 - .../testsuite/Magento/Framework/App/Route/ConfigTest.php | 1 - .../Magento/Framework/DB/Adapter/Pdo/MysqlTest.php | 1 - .../Magento/Framework/Reflection/MethodsMapTest.php | 2 -- .../testsuite/Magento/Framework/TranslateTest.php | 1 - .../Element/UiComponent/Config/Provider/TemplateTest.php | 1 - .../testsuite/Magento/ProductAlert/Model/ObserverTest.php | 1 - .../Controller/Adminhtml/Dashboard/IndexTest.php | 3 --- .../testsuite/Magento/Store/Model/StoreResolverTest.php | 1 - .../Magento/Theme/Model/Theme/ThemeProviderTest.php | 1 - .../Magento/Translation/Model/Js/PreProcessorTest.php | 1 - 25 files changed, 1 insertion(+), 41 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php index 7b14fe9159c57..2d0892b78c246 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductSearchTest.php @@ -154,7 +154,6 @@ private function compareFilterNames(array $a, array $b) */ public function testLayeredNavigationForConfigurableProducts() { - CacheCleaner::cleanAll(); $attributeCode = 'test_configurable'; /** @var Config $eavConfig */ @@ -258,7 +257,7 @@ private function getQueryProductsWithArrayOfCustomAttributes($attributeCode, $fi */ public function testFilterProductsByDropDownCustomAttribute() { - CacheCleaner::cleanAll(); + CacheCleaner::clean(['eav']); $attributeCode = 'second_test_configurable'; $optionValue = $this->getDefaultAttributeOptionValue($attributeCode); $query = <<<QUERY diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index b12630d70713a..d93f6d486c504 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -224,8 +224,6 @@ public function testRedirectsAndCustomInput() $urlRewriteModel->setId($urlRewriteModel->getId()); $urlRewriteModel->save(); - ObjectManager::getInstance()->get(\Magento\TestFramework\Helper\CacheCleaner::class)->cleanAll(); - //modifying query by adding spaces to avoid getting cached values. $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php index 7032199e9fc4c..8b18f89542494 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/ProductTest.php @@ -138,9 +138,6 @@ public function testSaveActionAndDuplicateWithUrlPathAttribute() $urlPathAttribute = $product->getCustomAttribute('url_path'); $this->assertEquals($urlPathAttribute->getValue(), $product->getSku()); - // clean cache - CacheCleaner::cleanAll(); - // dispatch Save&Duplicate action and check it $this->assertSaveAndDuplicateAction($product); } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ConfigTest.php index 36379adcee601..8320ef979180f 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ConfigTest.php @@ -31,7 +31,6 @@ protected function setUp(): void public function testGetEntityAttributeCodes() { $entityType = 'catalog_product'; - CacheCleaner::cleanAll(); $this->assertEquals( $this->config->getEntityAttributeCodes($entityType), $this->config->getEntityAttributeCodes($entityType) @@ -42,7 +41,6 @@ public function testGetAttribute() { $entityType = 'catalog_product'; $attributeCode = 'color'; - CacheCleaner::cleanAll(); $this->assertEquals( $this->config->getAttribute($entityType, $attributeCode), $this->config->getAttribute($entityType, $attributeCode) @@ -52,7 +50,6 @@ public function testGetAttribute() public function testGetEntityType() { $entityType = 'catalog_product'; - CacheCleaner::cleanAll(); $this->assertEquals( $this->config->getEntityType($entityType), $this->config->getEntityType($entityType) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Source/CountryofmanufactureTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Source/CountryofmanufactureTest.php index 33e82e9f6ddcc..8b8f54af2d387 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Source/CountryofmanufactureTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Source/CountryofmanufactureTest.php @@ -24,7 +24,6 @@ protected function setUp(): void public function testGetAllOptions() { - CacheCleaner::cleanAll(); $allOptions = $this->model->getAllOptions(); $cachedAllOptions = $this->model->getAllOptions(); $this->assertEquals($allOptions, $cachedAllOptions); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Attribute/Entity/AttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Attribute/Entity/AttributeTest.php index 5b9c7b267f188..7d9e9a48093cb 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Attribute/Entity/AttributeTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/Attribute/Entity/AttributeTest.php @@ -52,7 +52,6 @@ class AttributeTest extends \PHPUnit\Framework\TestCase */ protected function setUp(): void { - CacheCleaner::cleanAll(); $this->objectManager = Bootstrap::getObjectManager(); $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); $this->attributeRepository = $this->objectManager->get(AttributeRepository::class); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php index 8ad346af068b4..d5e7d94ec0cae 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CategoriesTest.php @@ -39,7 +39,6 @@ public function testModifyMeta() { $inputMeta = include __DIR__ . '/_files/input_meta_for_categories.php'; $expectedCategories = include __DIR__ . '/_files/expected_categories.php'; - CacheCleaner::cleanAll(); $this->assertCategoriesInMeta($expectedCategories, $this->object->modifyMeta($inputMeta)); // Verify cached data $this->assertCategoriesInMeta($expectedCategories, $this->object->modifyMeta($inputMeta)); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AddressMetadataTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AddressMetadataTest.php index 647c386e2b784..4443d170e388a 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AddressMetadataTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AddressMetadataTest.php @@ -19,7 +19,6 @@ class AddressMetadataTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { - CacheCleaner::cleanAll(); $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $objectManager->configure( [ diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php index c3e08b5294679..63d7019ee4f61 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php @@ -29,7 +29,6 @@ class CustomerMetadataTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { - CacheCleaner::cleanAll(); $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); $objectManager->configure( [\Magento\Framework\Api\ExtensionAttribute\Config\Reader::class => [ diff --git a/dev/tests/integration/testsuite/Magento/Directory/Block/DataTest.php b/dev/tests/integration/testsuite/Magento/Directory/Block/DataTest.php index ea2368a35c2f2..ccc1ea3f2f0b9 100644 --- a/dev/tests/integration/testsuite/Magento/Directory/Block/DataTest.php +++ b/dev/tests/integration/testsuite/Magento/Directory/Block/DataTest.php @@ -22,7 +22,6 @@ protected function setUp(): void public function testGetCountryHtmlSelect() { - CacheCleaner::cleanAll(); $result = $this->block->getCountryHtmlSelect(); $resultTwo = $this->block->getCountryHtmlSelect(); $this->assertEquals($result, $resultTwo); @@ -30,7 +29,6 @@ public function testGetCountryHtmlSelect() public function testGetRegionHtmlSelect() { - CacheCleaner::cleanAll(); $result = $this->block->getRegionHtmlSelect(); $resultTwo = $this->block->getRegionHtmlSelect(); $this->assertEquals($result, $resultTwo); diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php index a2865d52517fa..63fcfbd061877 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php @@ -33,7 +33,6 @@ protected function setUp(): void public function testGetEntityAttributeCodes() { $entityType = 'test'; - CacheCleaner::cleanAll(); $entityAttributeCodes1 = $this->config->getEntityAttributeCodes($entityType); $this->assertEquals( [ @@ -60,7 +59,6 @@ public function testGetEntityAttributeCodesWithObject() $testEntityType = Bootstrap::getObjectManager()->create(\Magento\Eav\Model\Entity\Type::class) ->loadByCode('test'); $attributeSetId = $testEntityType->getDefaultAttributeSetId(); - CacheCleaner::cleanAll(); $object = new DataObject( [ 'attribute_set_id' => $attributeSetId, @@ -86,7 +84,6 @@ public function testGetEntityAttributeCodesWithObject() public function testGetAttributes() { $entityType = 'test'; - CacheCleaner::cleanAll(); $attributes1 = $this->config->getAttributes($entityType); $expectedAttributeCodes = [ 'attribute_for_search_1', @@ -111,7 +108,6 @@ public function testGetAttributes() public function testGetAttribute() { $entityType = 'test'; - CacheCleaner::cleanAll(); $attribute1 = $this->config->getAttribute($entityType, 'attribute_for_search_1'); $this->assertEquals('attribute_for_search_1', $attribute1->getAttributeCode()); $this->assertEquals('varchar', $attribute1->getBackendType()); @@ -153,8 +149,6 @@ public function testGetAttributeWithCacheUserDefinedAttribute() $config = Bootstrap::getObjectManager()->create(\Magento\Eav\Model\Config::class); $updatedAttribute = $config->getAttribute($entityType, 'foo'); $this->assertEquals('foo', $updatedAttribute->getFrontendLabel()); - // Clean cache - CacheCleaner::cleanAll(); $config = Bootstrap::getObjectManager()->create(\Magento\Eav\Model\Config::class); // Check that attribute data has changed $updatedAttributeAfterCacheClean = $config->getAttribute($entityType, 'foo'); diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/Attribute/Frontend/DefaultFrontendTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/Attribute/Frontend/DefaultFrontendTest.php index b27e81129e1c3..cb7d288deb75a 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/Attribute/Frontend/DefaultFrontendTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/Attribute/Frontend/DefaultFrontendTest.php @@ -55,7 +55,6 @@ class DefaultFrontendTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { - CacheCleaner::cleanAll(); $this->objectManager = Bootstrap::getObjectManager(); $this->defaultFrontend = $this->objectManager->get(DefaultFrontend::class); diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/AttributeLoaderTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/AttributeLoaderTest.php index 7a0c66e7e2db2..817c37bca528b 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/AttributeLoaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/Entity/AttributeLoaderTest.php @@ -32,7 +32,6 @@ class AttributeLoaderTest extends \PHPUnit\Framework\TestCase protected function setUp(): void { - CacheCleaner::cleanAll(); $this->objectManager = Bootstrap::getObjectManager(); $this->attributeLoader = $this->objectManager->get(AttributeLoader::class); $entityType = $this->objectManager->create(\Magento\Eav\Model\Entity\Type::class) diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Config/InitialTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/Config/InitialTest.php index 43203d38e308f..2b3ebc217ab7b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Config/InitialTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Config/InitialTest.php @@ -24,7 +24,6 @@ protected function setUp(): void public function testGetMetadata() { - CacheCleaner::cleanAll(); $this->assertEquals( $this->objectManager->create(Config::class)->getMetadata(), $this->objectManager->create(Config::class)->getMetadata() @@ -37,7 +36,6 @@ public function testGetMetadata() */ public function testGetData($scope) { - CacheCleaner::cleanAll(); $this->assertEquals( $this->objectManager->create(Config::class)->getData($scope), $this->objectManager->create(Config::class)->getData($scope) diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigLoaderTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigLoaderTest.php index 1a2b8772c2dc5..ed4e15bd78a0c 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigLoaderTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/ObjectManager/ConfigLoaderTest.php @@ -24,7 +24,6 @@ protected function setUp(): void public function testLoad() { - CacheCleaner::cleanAll(); $data = $this->object->load('global'); $this->assertNotEmpty($data); $cachedData = $this->object->load('global'); diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Route/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/Route/ConfigTest.php index ff37b7d847921..d0c8c6083caee 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/App/Route/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Route/ConfigTest.php @@ -28,7 +28,6 @@ protected function setUp(): void */ public function testGetRouteFrontName($route, $scope) { - CacheCleaner::cleanAll(); $this->assertEquals( $this->objectManager->create(Config::class)->getRouteFrontName($route, $scope), $this->objectManager->create(Config::class)->getRouteFrontName($route, $scope) diff --git a/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php b/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php index 6e3391bd8959f..a93e8c198336e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/DB/Adapter/Pdo/MysqlTest.php @@ -27,7 +27,6 @@ protected function setUp(): void set_error_handler(null); $this->resourceConnection = Bootstrap::getObjectManager() ->get(ResourceConnection::class); - CacheCleaner::cleanAll(); } protected function tearDown(): void diff --git a/dev/tests/integration/testsuite/Magento/Framework/Reflection/MethodsMapTest.php b/dev/tests/integration/testsuite/Magento/Framework/Reflection/MethodsMapTest.php index 585933422edb8..cbe3c552544d4 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Reflection/MethodsMapTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Reflection/MethodsMapTest.php @@ -24,7 +24,6 @@ protected function setUp(): void public function testGetMethodsMap() { - CacheCleaner::cleanAll(); $data = $this->object->getMethodsMap(\Magento\Framework\Reflection\MethodsMap::class); $this->assertArrayHasKey('getMethodsMap', $data); $cachedData = $this->object->getMethodsMap(\Magento\Framework\Reflection\MethodsMap::class); @@ -33,7 +32,6 @@ public function testGetMethodsMap() public function testGetMethodParams() { - CacheCleaner::cleanAll(); $data = $this->object->getMethodParams( \Magento\Framework\Reflection\MethodsMap::class, 'getMethodParams' diff --git a/dev/tests/integration/testsuite/Magento/Framework/TranslateTest.php b/dev/tests/integration/testsuite/Magento/Framework/TranslateTest.php index 5b48a9169c577..b216831bde33e 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/TranslateTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/TranslateTest.php @@ -94,7 +94,6 @@ protected function setUp(): void public function testLoadData() { $data = $this->translate->loadData(null, true)->getData(); - CacheCleaner::cleanAll(); $this->translate->loadData()->getData(); $dataCached = $this->translate->loadData()->getData(); $this->assertEquals($data, $dataCached); diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Element/UiComponent/Config/Provider/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Element/UiComponent/Config/Provider/TemplateTest.php index f58882ee51493..92a51b85c8c4b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Element/UiComponent/Config/Provider/TemplateTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Element/UiComponent/Config/Provider/TemplateTest.php @@ -49,7 +49,6 @@ public function testGetTemplate() \Magento\TestFramework\Helper\Bootstrap::getInstance()->loadArea('adminhtml'); $this->objectManager->get(\Magento\Framework\View\DesignInterface::class) ->setDesignTheme('FrameworkViewUiComponent/default'); - CacheCleaner::cleanAll(); $resultOne = $this->model->getTemplate('test.xml'); $resultTwo = $this->model->getTemplate('test.xml'); diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php b/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php index 287564722ced6..b28788bc649a1 100644 --- a/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/Model/ObserverTest.php @@ -93,7 +93,6 @@ public function testProcessPortuguese() $secondStore = $storeRepository->get('fixture_second_store'); // check if Portuguese language is specified for the second store - CacheCleaner::cleanAll(); $storeResolver = $this->_objectManager->get(Resolver::class); $storeResolver->emulate($secondStore->getId()); $this->assertEquals('pt_BR', $storeResolver->getLocale()); diff --git a/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php b/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php index 9358d761b28b2..63c5e04bac84a 100644 --- a/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php @@ -44,7 +44,6 @@ public function testExecute() { $content = include __DIR__ . '/../../../_files/validContent.php'; - CacheCleaner::cleanAll(); $this->contentProviderMock->expects($this->any()) ->method('getContent') ->willReturn($content); @@ -62,7 +61,6 @@ public function testExecute() public function testExecuteEmptyContent() { - CacheCleaner::cleanAll(); $this->contentProviderMock->expects($this->any()) ->method('getContent') ->willReturn('[]'); @@ -77,7 +75,6 @@ public function testExecuteEmptyContent() public function testExecuteFalseContent() { - CacheCleaner::cleanAll(); $this->contentProviderMock->expects($this->any()) ->method('getContent') ->willReturn(false); diff --git a/dev/tests/integration/testsuite/Magento/Store/Model/StoreResolverTest.php b/dev/tests/integration/testsuite/Magento/Store/Model/StoreResolverTest.php index 53c58cc693a6e..c20b0ed27bf52 100644 --- a/dev/tests/integration/testsuite/Magento/Store/Model/StoreResolverTest.php +++ b/dev/tests/integration/testsuite/Magento/Store/Model/StoreResolverTest.php @@ -28,7 +28,6 @@ public function testGetStoreData() $storeResolver = $this->objectManager->get(\Magento\Store\Model\StoreResolver::class); $storesDataRead = $methodReadStoresData->invoke($storeResolver); - CacheCleaner::cleanAll(); $storesData = $methodGetStoresData->invoke($storeResolver); $storesDataCached = $methodGetStoresData->invoke($storeResolver); $this->assertEquals($storesDataRead, $storesData); diff --git a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/ThemeProviderTest.php b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/ThemeProviderTest.php index 2f3d7065e5339..e2895a478b8d9 100644 --- a/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/ThemeProviderTest.php +++ b/dev/tests/integration/testsuite/Magento/Theme/Model/Theme/ThemeProviderTest.php @@ -33,7 +33,6 @@ protected function setUp(): void $this->themeProviderOne = $objectManager->create(ThemeProvider::class); $this->themeProviderTwo = clone $this->themeProviderOne; $this->themeCollection = $objectManager->create(ThemeCollection::class); - CacheCleaner::clean(); } public function testGetThemeById() diff --git a/dev/tests/integration/testsuite/Magento/Translation/Model/Js/PreProcessorTest.php b/dev/tests/integration/testsuite/Magento/Translation/Model/Js/PreProcessorTest.php index 4bc1c5b55ade5..842912546ece8 100644 --- a/dev/tests/integration/testsuite/Magento/Translation/Model/Js/PreProcessorTest.php +++ b/dev/tests/integration/testsuite/Magento/Translation/Model/Js/PreProcessorTest.php @@ -82,7 +82,6 @@ protected function tearDown(): void */ public function testProcess(string $content, string $translation) { - CacheCleaner::cleanAll(); $this->assertEquals($translation, $this->model->translate($content)); } From 09293a587a174c463c8f3d3ff5de775bf372c97c Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 25 Nov 2020 07:21:45 -0600 Subject: [PATCH 113/346] MC-38787: Admin Product Grid Page indicator issue --- ...hProductGridByStringNoClearActionGroup.xml | 2 +- ...dPageNumberSetsToOneAfterNewSearchTest.xml | 60 +++++++++++-------- ...GridAssertCurrentPageNumberActionGroup.xml | 22 +++++++ ...minGridAssertTotalPageCountActionGroup.xml | 22 +++++++ .../AdminGridGoToNextPageActionGroup.xml | 19 ++++++ 5 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertCurrentPageNumberActionGroup.xml create mode 100644 app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertTotalPageCountActionGroup.xml create mode 100644 app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridGoToNextPageActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml index a763f37ed153f..95ddfd37c0037 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml @@ -13,7 +13,7 @@ <description>Searches the Admin Products grid by string without clearing filters.</description> </annotations> <arguments> - <argument name="keyword" type="string"/> + <argument name="keyword" defaultValue="" type="string"/> </arguments> <fillField selector="{{AdminProductGridFilterSection.keywordSearch}}" userInput="{{keyword}}" stepKey="fillKeywordSearchField"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml index 0cc57ba94dac6..f833171166141 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml @@ -9,7 +9,6 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="AdminGridPageNumberSetsToOneAfterNewSearchTest"> - <annotations> <features value="Catalog"/> <stories value="Catalog grid"/> @@ -27,27 +26,28 @@ <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="goToProductCatalog"/> <actionGroup ref="ResetProductGridToDefaultViewActionGroup" stepKey="resetProductGridToDefaultView"/> <actionGroup ref="DeleteProductsIfTheyExistActionGroup" stepKey="deleteProductIfTheyExist"/> - <createData stepKey="category1" entity="SimpleSubCategory"/> - <createData stepKey="simpleProduct1" entity="SimpleProduct"> + <!-- Create required prerequisites --> + <createData entity="SimpleSubCategory" stepKey="category1"/> + <createData entity="SimpleProduct" stepKey="simpleProduct1"> <requiredEntity createDataKey="category1"/> </createData> - <createData stepKey="simpleProduct2" entity="SimpleProduct"> + <createData entity="SimpleProduct" stepKey="simpleProduct2"> <requiredEntity createDataKey="category1"/> </createData> - <createData stepKey="simpleProduct3" entity="SimpleProduct"> + <createData entity="SimpleProduct" stepKey="simpleProduct3"> <requiredEntity createDataKey="category1"/> </createData> - <createData stepKey="simpleProduct4" entity="SimpleProduct"> + <createData entity="SimpleProduct" stepKey="simpleProduct4"> <requiredEntity createDataKey="category1"/> </createData> - <createData stepKey="virtualProduct1" entity="VirtualProduct"> + <createData entity="VirtualProduct" stepKey="virtualProduct1"> <requiredEntity createDataKey="category1"/> </createData> - <createData stepKey="virtualProduct2" entity="VirtualProduct"> + <createData entity="VirtualProduct" stepKey="virtualProduct2"> <requiredEntity createDataKey="category1"/> </createData> - <createData stepKey="virtualProduct3" entity="VirtualProduct"> + <createData entity="VirtualProduct" stepKey="virtualProduct3"> <requiredEntity createDataKey="category1"/> </createData> </before> @@ -59,39 +59,47 @@ </actionGroup> <actionGroup ref="AdminClearFiltersActionGroup" stepKey="clearFilters"/> - <deleteData stepKey="deleteCategory1" createDataKey="category1"/> - - <deleteData stepKey="deleteSimpleProduct1" createDataKey="simpleProduct1"/> - <deleteData stepKey="deleteSimpleProduct2" createDataKey="simpleProduct2"/> - <deleteData stepKey="deleteSimpleProduct3" createDataKey="simpleProduct3"/> - <deleteData stepKey="deleteSimpleProduct4" createDataKey="simpleProduct4"/> - <deleteData stepKey="deleteVirtualProduct1" createDataKey="virtualProduct1"/> - <deleteData stepKey="deleteVirtualProduct2" createDataKey="virtualProduct2"/> - <deleteData stepKey="deleteVirtualProduct3" createDataKey="virtualProduct3"/> + <!-- Delete prerequisites --> + <deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/> + <deleteData createDataKey="simpleProduct3" stepKey="deleteSimpleProduct3"/> + <deleteData createDataKey="simpleProduct4" stepKey="deleteSimpleProduct4"/> + <deleteData createDataKey="virtualProduct1" stepKey="deleteVirtualProduct1"/> + <deleteData createDataKey="virtualProduct2" stepKey="deleteVirtualProduct2"/> + <deleteData createDataKey="virtualProduct3" stepKey="deleteVirtualProduct3"/> + <deleteData createDataKey="category1" stepKey="deleteCategory1"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="goToProductCatalog"/> + <!-- Set the product grid to display one product per page --> <actionGroup ref="AdminDataGridSelectCustomPerPageActionGroup" stepKey="select1ProductPerPage"> <argument name="perPage" value="ProductPerPage.productCount"/> </actionGroup> + <!-- Performing the first search and assertions --> <actionGroup ref="SearchProductGridByStringNoClearActionGroup" stepKey="searchForSimpleProduct"> <argument name="keyword" value="SimpleProduct"/> </actionGroup> + <actionGroup ref="AdminGridAssertTotalPageCountActionGroup" stepKey="waitForTotalPagesCountFourToBeVisible"> + <argument name="expectedTotalPageCount" value="4"/> + </actionGroup> + <actionGroup ref="AdminGridGoToNextPageActionGroup" stepKey="clickNextPageProductGrid"/> + <actionGroup ref="AdminGridAssertCurrentPageNumberActionGroup" stepKey="assertCurrentPageIsTwoOnProductGridFirstSearch"> + <argument name="expectedCurrentPageNumber" value="2"/> + </actionGroup> - <waitForElementVisible selector="{{AdminDataGridPaginationSection.totalPagesCount('4')}}" stepKey="seeTotalPagesIsFourOnFirstSearch"/> - <comment userInput="Go to the next page" stepKey="nextPage"/> - <click selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="clickNextPageProductGrid"/> - <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="2" stepKey="seeOnSecondPageProductGridOnFirstSearch"/> - + <!-- Performing the second search and assertions of successful current page number reset --> <actionGroup ref="SearchProductGridByStringNoClearActionGroup" stepKey="searchForVirtualProduct"> <argument name="keyword" value="VirtualProduct"/> </actionGroup> - - <waitForElementVisible selector="{{AdminDataGridPaginationSection.totalPagesCount('3')}}" stepKey="seeTotalPagesIsThreeOnSecondSearch"/> - <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="1" stepKey="seeOnFirstPageProductGridOnSecondSearch"/> + <actionGroup ref="AdminGridAssertTotalPageCountActionGroup" stepKey="waitForTotalPagesCountThreeToBeVisible"> + <argument name="expectedTotalPageCount" value="3"/> + </actionGroup> + <actionGroup ref="AdminGridAssertCurrentPageNumberActionGroup" stepKey="assertCurrentPageIsOneOnProductGridSecondSearch"> + <argument name="expectedCurrentPageNumber" value="1"/> + </actionGroup> </test> </tests> diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertCurrentPageNumberActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertCurrentPageNumberActionGroup.xml new file mode 100644 index 0000000000000..1765dbe1e7fcd --- /dev/null +++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertCurrentPageNumberActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminGridAssertCurrentPageNumberActionGroup"> + <annotations> + <description> + Assert current page number on admin grid + </description> + </annotations> + <arguments> + <argument name="expectedCurrentPageNumber" defaultValue="1" type="string"/> + </arguments> + + <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="{{expectedCurrentPageNumber}}" stepKey="seeCurrentPageNumberOnGrid"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertTotalPageCountActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertTotalPageCountActionGroup.xml new file mode 100644 index 0000000000000..402bd077f9fbb --- /dev/null +++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridAssertTotalPageCountActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminGridAssertTotalPageCountActionGroup"> + <annotations> + <description> + Assert total page count on admin grid + </description> + </annotations> + <arguments> + <argument name="expectedTotalPageCount" defaultValue="1" type="string"/> + </arguments> + + <waitForElementVisible selector="{{AdminDataGridPaginationSection.totalPagesCount('expectedTotalPageCount')}}" stepKey="waitForTotalPagesCountToBeVisible"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridGoToNextPageActionGroup.xml b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridGoToNextPageActionGroup.xml new file mode 100644 index 0000000000000..7da082a279688 --- /dev/null +++ b/app/code/Magento/Ui/Test/Mftf/ActionGroup/AdminGridGoToNextPageActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminGridGoToNextPageActionGroup"> + <annotations> + <description> + Go to next page of the admin grid. + </description> + </annotations> + + <click selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="clickNextPageOnGrid"/> + </actionGroup> +</actionGroups> From 33c7cc810972871a5067ffd7772c71368c44b668 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Wed, 25 Nov 2020 16:05:02 +0200 Subject: [PATCH 114/346] MC-35717: Admin can not add a Product with a Customizable Option (File) to Order by SKU --- .../Model/Product/Option/Type/File.php | 19 +++++++++++++++++-- .../Catalog/Test/Mftf/Data/ProductData.xml | 4 ++++ .../catalog/product/composite/configure.js | 6 ++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/File.php b/app/code/Magento/Catalog/Model/Product/Option/Type/File.php index 77ef8ef4853e1..de7044a41f1d3 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Type/File.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Type/File.php @@ -6,10 +6,11 @@ namespace Magento\Catalog\Model\Product\Option\Type; +use Magento\Catalog\Model\Product\Exception as ProductException; +use Magento\Catalog\Helper\Product as ProductHelper; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Filesystem; use Magento\Framework\Exception\LocalizedException; -use Magento\Catalog\Model\Product\Exception as ProductException; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\App\ObjectManager; @@ -91,6 +92,11 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType */ private $filesystem; + /** + * @var ProductHelper + */ + private $productHelper; + /** * @param \Magento\Checkout\Model\Session $checkoutSession * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig @@ -103,6 +109,7 @@ class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType * @param array $data * @param Filesystem $filesystem * @param Json|null $serializer + * @param ProductHelper|null $productHelper * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -116,7 +123,8 @@ public function __construct( \Magento\Framework\Escaper $escaper, array $data = [], Filesystem $filesystem = null, - Json $serializer = null + Json $serializer = null, + ProductHelper $productHelper = null ) { $this->_itemOptionFactory = $itemOptionFactory; $this->_urlBuilder = $urlBuilder; @@ -129,6 +137,7 @@ public function __construct( $this->validatorInfo = $validatorInfo; $this->validatorFile = $validatorFile; $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->productHelper = $productHelper ?: ObjectManager::getInstance()->get(ProductHelper::class); parent::__construct($checkoutSession, $scopeConfig, $data); } @@ -223,6 +232,12 @@ public function validateUserValue($values) $this->setIsValid(true); $option = $this->getOption(); + if (isset($values['files_prefix'])) { + $processingParams = ['files_prefix' => $values['files_prefix']]; + $processingParams = array_merge($this->_getProcessingParams()->getData(), $processingParams); + $this->productHelper->addParamsToBuyRequest($this->getRequest(), $processingParams); + } + /* * Check whether we receive uploaded file or restore file by: reorder/edit configuration or * previous configuration with no newly uploaded file diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml index 716c4b07d2f1d..be09f999f97fb 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml @@ -581,6 +581,10 @@ <var key="sku" entityType="product" entityKey="sku" /> <requiredEntity type="product_option">ProductOptionValueDropdown</requiredEntity> </entity> + <entity name="productWithFileOption" type="product"> + <var key="sku" entityType="product" entityKey="sku" /> + <requiredEntity type="product_option">ProductOptionFile</requiredEntity> + </entity> <entity name="productWithDropdownAndFieldOptions" type="product"> <var key="sku" entityType="product" entityKey="sku" /> <requiredEntity type="product_option">ProductOptionValueDropdown</requiredEntity> diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js index 1ac2a4ffadaae..fcb193b9565ef 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js @@ -607,6 +607,7 @@ define([ * @param method can be 'item_confirm', 'item_restore', 'current_confirmed_to_form', 'form_confirmed_to_confirmed' */ _processFieldsData: function (method) { + var self = this; /** * Internal function for rename fields names of some list type @@ -652,6 +653,11 @@ define([ for (var i = 0; i < elms.length; i++) { if (elms[i].name && elms[i].type == 'file') { elms[i].name = elms[i].name.replace(patternFlat, replacementFlat); + self.blockFormFields.insert(new Element('input', { + type: 'hidden', + name: 'options[files_prefix]'.replace(pattern, replacement), + value: 'item_' + itemId + '_' + })); } else if (elms[i].name) { elms[i].name = elms[i].name.replace(pattern, replacement); } From c3cfd8abf8ee32be94303011288b5b2e4e487850 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Tue, 24 Nov 2020 17:01:38 -0600 Subject: [PATCH 115/346] MC-36787: Cannot mass update Enable Qty Increments & Qty Increments attributes - Fix column not found: 1054 Unknown column 'use_config_enable_qty_increments' in 'field list' --- ...MassUpdateProductAttributesActionGroup.xml | 3 +- ...sUpdateProductQtyIncrementsActionGroup.xml | 27 +++++++ ...dateAttributesAdvancedInventorySection.xml | 6 ++ ...dminMassUpdateProductQtyIncrementsTest.xml | 81 +++++++++++++++++++ .../product/edit/action/inventory.phtml | 2 +- .../Plugin/MassUpdateProductAttribute.php | 12 ++- 6 files changed, 128 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminMassUpdateProductQtyIncrementsActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductQtyIncrementsTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminClickMassUpdateProductAttributesActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminClickMassUpdateProductAttributesActionGroup.xml index 90cc7666eb92f..ec3d26e8a3f36 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminClickMassUpdateProductAttributesActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminClickMassUpdateProductAttributesActionGroup.xml @@ -14,6 +14,7 @@ </annotations> <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickDropdown"/> <click selector="{{AdminProductGridSection.bulkActionOption('Update attributes')}}" stepKey="clickOption"/> - <seeInCurrentUrl url="catalog/product_action_attribute/edit/" stepKey="seeInUrl"/> + <waitForPageLoad stepKey="waitForBulkUpdatePage"/> + <seeInCurrentUrl url="{{ProductAttributesEditPage.url}}" stepKey="seeInUrl"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminMassUpdateProductQtyIncrementsActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminMassUpdateProductQtyIncrementsActionGroup.xml new file mode 100644 index 0000000000000..a39ac8c3f5d2b --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminMassUpdateProductQtyIncrementsActionGroup.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminMassUpdateProductQtyIncrementsActionGroup"> + <arguments> + <argument name="enableQtyIncrements" type="string" defaultValue="Yes"/> + <argument name="qtyIncrements" type="string" defaultValue="2"/> + </arguments> + <click selector="{{AdminUpdateAttributesAdvancedInventorySection.inventory}}" stepKey="openInventoryTab"/> + <checkOption selector="{{AdminUpdateAttributesAdvancedInventorySection.changeEnableQtyIncrements}}" stepKey="changeEnableQtyIncrements"/> + <uncheckOption selector="{{AdminUpdateAttributesAdvancedInventorySection.useConfigEnableQtyIncrements}}" stepKey="uncheckUseConfigEnableQtyIncrements"/> + <selectOption selector="{{AdminUpdateAttributesAdvancedInventorySection.enableQtyIncrements}}" userInput="{{enableQtyIncrements}}" stepKey="setEnableQtyIncrements"/> + <checkOption selector="{{AdminUpdateAttributesAdvancedInventorySection.changeQtyIncrements}}" stepKey="changeQtyIncrements"/> + <uncheckOption selector="{{AdminUpdateAttributesAdvancedInventorySection.useConfigQtyIncrements}}" stepKey="uncheckUseConfigQtyIncrements"/> + <fillField selector="{{AdminUpdateAttributesAdvancedInventorySection.qtyIncrements}}" userInput="{{qtyIncrements}}" stepKey="setQtyIncrements"/> + <click selector="{{AdminUpdateAttributesSection.saveButton}}" stepKey="save"/> + <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitVisibleSuccessMessage"/> + <see selector="{{AdminMessagesSection.success}}" userInput="Message is added to queue" stepKey="seeSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection/AdminUpdateAttributesAdvancedInventorySection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection/AdminUpdateAttributesAdvancedInventorySection.xml index 92dadbdd26c2d..9881545fac9cd 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection/AdminUpdateAttributesAdvancedInventorySection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection/AdminUpdateAttributesAdvancedInventorySection.xml @@ -13,5 +13,11 @@ <element name="qty" type="input" selector="#inventory_qty"/> <element name="changeStockAvailability" type="checkbox" selector="#inventory_stock_availability_checkbox"/> <element name="stockAvailability" type="select" selector="//select[@name='inventory[is_in_stock]']"/> + <element name="enableQtyIncrements" type="select" selector="#inventory_enable_qty_increments"/> + <element name="useConfigEnableQtyIncrements" type="checkbox" selector="#inventory_use_config_enable_qty_increments"/> + <element name="changeEnableQtyIncrements" type="checkbox" selector="#inventory_enable_qty_increments_checkbox"/> + <element name="qtyIncrements" type="input" selector="#inventory_qty_increments"/> + <element name="useConfigQtyIncrements" type="checkbox" selector="#inventory_use_config_qty_increments"/> + <element name="changeQtyIncrements" type="checkbox" selector="#inventory_qty_increments_checkbox"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductQtyIncrementsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductQtyIncrementsTest.xml new file mode 100644 index 0000000000000..aa82b092a0a98 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductQtyIncrementsTest.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminMassUpdateProductQtyIncrementsTest"> + <annotations> + <features value="Catalog"/> + <stories value="Mass update advanced inventory attributes"/> + <title value="Admin should be able to mass update product qty increments"/> + <description value="Admin should be able to mass update product qty increments"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-39359"/> + <useCaseId value="MC-36787"/> + <group value="catalog"/> + <group value="CatalogInventory"/> + <group value="product_attributes"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="ApiSimpleProduct" stepKey="createProductOne"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiSimpleProduct" stepKey="createProductTwo"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createProductOne" stepKey="deleteProductOne"/> + <deleteData createDataKey="createProductTwo" stepKey="deleteProductTwo"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="ClearProductsFilterActionGroup" stepKey="clearProductFilter"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> + </after> + <!-- Navigate to products list page and select created products --> + <actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndex"/> + <actionGroup ref="SearchProductGridByKeyword2ActionGroup" stepKey="searchByKeyword"> + <argument name="keyword" value="api-simple-product"/> + </actionGroup> + <actionGroup ref="SortProductsByIdDescendingActionGroup" stepKey="sortProductsByIdDescending"/> + <click selector="{{AdminProductGridSection.productGridCheckboxOnRow('1')}}" stepKey="clickCheckbox1"/> + <click selector="{{AdminProductGridSection.productGridCheckboxOnRow('2')}}" stepKey="clickCheckbox2"/> + <!-- Mass update qty increments --> + <actionGroup ref="AdminClickMassUpdateProductAttributesActionGroup" stepKey="clickMassUpdateProductAttributes"/> + <actionGroup ref="AdminMassUpdateProductQtyIncrementsActionGroup" stepKey="updateQtyIncrements"> + <argument name="enableQtyIncrements" value="Yes"/> + <argument name="qtyIncrements" value="2"/> + </actionGroup> + <!-- Start message queue for product attribute consumer --> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue"> + <argument name="consumerName" value="{{AdminProductAttributeUpdateMessageConsumerData.consumerName}}"/> + <argument name="maxMessages" value="{{AdminProductAttributeUpdateMessageConsumerData.messageLimit}}"/> + </actionGroup> + <!-- Open first product for edit and assert that qty increment is updated --> + <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPage"> + <argument name="productId" value="$createProductOne.id$"/> + </actionGroup> + <waitForPageLoad stepKey="waitForProductPageLoad"/> + <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickOnAdvancedInventoryLink"/> + <seeOptionIsSelected selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrements}}" userInput="Yes" stepKey="assertEnableQtyIncrementsValue"/> + <dontSeeCheckboxIsChecked selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrementsUseConfigSettings}}" stepKey="assertEnableQtyIncrementsUseConfigSettings"/> + <seeInField selector="{{AdminProductFormAdvancedInventorySection.qtyIncrements}}" userInput="2" stepKey="assertQtyIncrementsValue"/> + <dontSeeCheckboxIsChecked selector="{{AdminProductFormAdvancedInventorySection.qtyIncrementsUseConfigSettings}}" stepKey="assertQtyIncrementsUseConfigSettings"/> + <!-- Open second product for edit and assert that qty increment is updated --> + <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="goToProductEditPage2"> + <argument name="productId" value="$createProductTwo.id$"/> + </actionGroup> + <waitForPageLoad stepKey="waitForProductPageLoad2"/> + <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickOnAdvancedInventoryLink2"/> + <seeOptionIsSelected selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrements}}" userInput="Yes" stepKey="assertEnableQtyIncrementsValue2"/> + <dontSeeCheckboxIsChecked selector="{{AdminProductFormAdvancedInventorySection.enableQtyIncrementsUseConfigSettings}}" stepKey="assertEnableQtyIncrementsUseConfigSettings2"/> + <seeInField selector="{{AdminProductFormAdvancedInventorySection.qtyIncrements}}" userInput="2" stepKey="assertQtyIncrementsValue2"/> + <dontSeeCheckboxIsChecked selector="{{AdminProductFormAdvancedInventorySection.qtyIncrementsUseConfigSettings}}" stepKey="assertQtyIncrementsUseConfigSettings2"/> + </test> +</tests> diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/inventory.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/inventory.phtml index 344123cbe5640..646512d98582e 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/inventory.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/edit/action/inventory.phtml @@ -334,7 +334,7 @@ if (!is_numeric($defaultMinSaleQty)) { </div> <div class="field choice"> <input type="checkbox" id="inventory_use_config_enable_qty_increments" - name="<?= /* @noEscape */ $block->getFieldSuffix() ?>[use_config_enable_qty_increments]" + name="<?= /* @noEscape */ $block->getFieldSuffix() ?>[use_config_enable_qty_inc]" value="1" data-role="toggle-editability" checked="checked" diff --git a/app/code/Magento/CatalogInventory/Plugin/MassUpdateProductAttribute.php b/app/code/Magento/CatalogInventory/Plugin/MassUpdateProductAttribute.php index 2dd47eae16959..9351abf0ead3d 100644 --- a/app/code/Magento/CatalogInventory/Plugin/MassUpdateProductAttribute.php +++ b/app/code/Magento/CatalogInventory/Plugin/MassUpdateProductAttribute.php @@ -64,6 +64,14 @@ class MassUpdateProductAttribute * @var ProductRepositoryInterface */ private $productRepository; + + /** + * @var array + */ + private $useConfigFieldMap = [ + 'enable_qty_increments' => 'use_config_enable_qty_inc' + ]; + /** * @param \Magento\CatalogInventory\Model\Indexer\Stock\Processor $stockIndexerProcessor * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper @@ -146,7 +154,9 @@ private function addConfigSettings($inventoryData) { $options = $this->stockConfiguration->getConfigItemOptions(); foreach ($options as $option) { - $useConfig = 'use_config_' . $option; + $useConfig = isset($this->useConfigFieldMap[$option]) + ? $this->useConfigFieldMap[$option] + : 'use_config_' . $option; if (isset($inventoryData[$option]) && !isset($inventoryData[$useConfig])) { $inventoryData[$useConfig] = 0; } From f13958e4570cf1bbd2976c1a037a043b4c4962ae Mon Sep 17 00:00:00 2001 From: engcom-Echo <engcom-vendorworker-echo@adobe.com> Date: Thu, 26 Nov 2020 11:19:12 +0200 Subject: [PATCH 116/346] MC-37807: Link to a file of a Product with Customizable Option(File) is not available throughout a multishipping checkout process --- .../view/frontend/templates/checkout/item/default.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml b/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml index a696a693fa002..5d7f06475af28 100644 --- a/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml +++ b/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml @@ -13,7 +13,7 @@ <?php $_formatedOptionValue = $block->getFormatedOptionValue($_option) ?> <dt><?= $block->escapeHtml($_option['label']) ?></dt> <dd<?= (isset($_formatedOptionValue['full_view']) ? ' class="tooltip wrapper"' : '') ?>> - <?= $block->escapeHtml($_formatedOptionValue['value'], ['span']) ?> + <?= $block->escapeHtml($_formatedOptionValue['value'], ['span', 'a']) ?> <?php if (isset($_formatedOptionValue['full_view'])) : ?> <dl class="item options tooltip content"> <dt><?= $block->escapeHtml($_option['label']) ?></dt> From a8c72b00d7d30a60499e0aea085fade9df480b82 Mon Sep 17 00:00:00 2001 From: "taras.gamanov" <engcom-vendorworker-hotel@adobe.com> Date: Thu, 26 Nov 2020 11:55:55 +0200 Subject: [PATCH 117/346] flaky test has been updated (MC-12599) --- ...ConfigsChangesIsNotAffectedStartedCheckoutProcessTest.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckConfigsChangesIsNotAffectedStartedCheckoutProcessTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckConfigsChangesIsNotAffectedStartedCheckoutProcessTest.xml index df229c4b6ed78..ffbd6152af80b 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckConfigsChangesIsNotAffectedStartedCheckoutProcessTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/AdminCheckConfigsChangesIsNotAffectedStartedCheckoutProcessTest.xml @@ -58,6 +58,11 @@ <argument name="address" value="US_Address_TX"/> </actionGroup> + <!-- Select Free Shipping --> + <actionGroup ref="StorefrontSetShippingMethodActionGroup" stepKey="setShippingMethodFreeShipping"> + <argument name="shippingMethodName" value="Free Shipping"/> + </actionGroup> + <!-- Assert Free Shipping checkbox --> <seeCheckboxIsChecked selector="{{CheckoutShippingMethodsSection.shippingMethodFreeShipping}}" stepKey="freeShippingMethodCheckboxIsChecked"/> From 66a0607d8d781b2ae84c90e8afc3ad949706cf7a Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi <stailx1@gmail.com> Date: Thu, 26 Nov 2020 13:12:52 +0100 Subject: [PATCH 118/346] int type for price indexer --- .../Model/Indexer/ProductPriceIndexFilter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php index 2ad7ca9f14963..2b37c9099a0e6 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/ProductPriceIndexFilter.php @@ -105,7 +105,7 @@ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = } if (!empty($entityIds)) { - $select->where('stock_item.product_id in (?)', $entityIds, \Zend_Db::INT_TYPE); + $select->where('stock_item.product_id IN (?)', $entityIds, \Zend_Db::INT_TYPE); } $select->group('stock_item.product_id'); @@ -121,7 +121,7 @@ public function modifyPrice(IndexTableStructure $priceTable, array $entityIds = foreach ($batchSelectIterator as $select) { $productIds = null; foreach ($connection->query($select)->fetchAll() as $row) { - $productIds[] = $row['product_id']; + $productIds[] = (int) $row['product_id']; } if ($productIds !== null) { $where = [$priceTable->getEntityField() .' IN (?)' => $productIds]; From f13157df893426f6a4d5a031b046add21c319693 Mon Sep 17 00:00:00 2001 From: Oleh Usik <o.usik@atwix.com> Date: Thu, 26 Nov 2020 23:46:08 +0200 Subject: [PATCH 119/346] Update dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php --- .../Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index d93f6d486c504..6188e67eaa393 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -223,7 +223,7 @@ public function testRedirectsAndCustomInput() $urlRewriteModel->setRedirectType('301'); $urlRewriteModel->setId($urlRewriteModel->getId()); $urlRewriteModel->save(); - +ObjectManager::getInstance()->get(\Magento\TestFramework\Helper\CacheCleaner::class)->clean(['eav']); //modifying query by adding spaces to avoid getting cached values. $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), From 6c2d07c4a3b9cfd3191e2382efdbf2ef834d19cf Mon Sep 17 00:00:00 2001 From: Oleh Usik <o.usik@atwix.com> Date: Thu, 26 Nov 2020 23:46:58 +0200 Subject: [PATCH 120/346] Update dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php --- .../Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index 6188e67eaa393..2f6fc2ee112fa 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -223,7 +223,7 @@ public function testRedirectsAndCustomInput() $urlRewriteModel->setRedirectType('301'); $urlRewriteModel->setId($urlRewriteModel->getId()); $urlRewriteModel->save(); -ObjectManager::getInstance()->get(\Magento\TestFramework\Helper\CacheCleaner::class)->clean(['eav']); + ObjectManager::getInstance()->get(\Magento\TestFramework\Helper\CacheCleaner::class)->clean(['eav']); //modifying query by adding spaces to avoid getting cached values. $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), From 3067d2d9ec14e7dec195977c90ae7f3057d5728f Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Thu, 26 Nov 2020 05:25:48 -0600 Subject: [PATCH 121/346] MC-39354: Magento 2.4.1 - REST API - Shipping and Billing Address - Issues with Custom Attributes Values - Adding billing address custom customer attribute --- ...GuestShippingInformationManagementTest.php | 47 +++++++++ ...mer_address_with_custom_text_attribute.php | 96 +++++++++++++++++++ ...ss_with_custom_text_attribute_rollback.php | 33 +++++++ 3 files changed, 176 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute.php create mode 100644 dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Checkout/Api/GuestShippingInformationManagementTest.php b/dev/tests/integration/testsuite/Magento/Checkout/Api/GuestShippingInformationManagementTest.php index 4cb4b00d08a84..e54ce16051d60 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/Api/GuestShippingInformationManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/Api/GuestShippingInformationManagementTest.php @@ -12,6 +12,8 @@ use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\ShippingAssignmentInterface; use Magento\TestFramework\Helper\Bootstrap; @@ -120,6 +122,51 @@ public function testDifferentAddresses(bool $swapShipping): void $this->management->saveAddressInformation($idMask->getMaskedId(), $shippingInformation); } + /** + * Test save address information with customer custom address attribute for quote + * + * @return void + * + * @throws LocalizedException + * @throws NoSuchEntityException + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/Customer/_files/customer_address_with_custom_text_attribute.php + */ + public function testSaveAddressInformationWithCustomerCustomAddressAttribute(): void + { + $carts = $this->cartRepo->getList( + $this->searchCriteria->addFilter('reserved_order_id', 'test01')->create() + )->getItems(); + $currentQuote = array_pop($carts); + $guestCustomer = $this->customerRepo->get('JohnDoe@mail.com'); + + $customerCustomAddressAttribute = $guestCustomer->getCustomAttributes(); + + /** @var ShippingAssignmentInterface $shippingAssignment */ + $shippingAssignment = $currentQuote->getExtensionAttributes()->getShippingAssignments()[0]; + $shippingAddress = $shippingAssignment->getShipping()->getAddress(); + $billingAddress = $currentQuote->getBillingAddress(); + + if ($customerCustomAddressAttribute) { + $shippingAddress->setCustomAttributes($customerCustomAddressAttribute); + $billingAddress->setCustomAttributes($customerCustomAddressAttribute); + } + + /** @var ShippingInformationInterface $shippingInformation */ + $shippingInformation = $this->shippingFactory->create(); + $shippingInformation->setBillingAddress($billingAddress); + $shippingInformation->setShippingAddress($shippingAddress); + $shippingInformation->setShippingMethodCode('flatrate'); + $shippingInformation->setShippingCarrierCode('flatrate'); + /** @var QuoteIdMask $idMask */ + $idMask = $this->maskFactory->create(); + $idMask->load($currentQuote->getId(), 'quote_id'); + + $paymentDetails = $this->management->saveAddressInformation($idMask->getMaskedId(), $shippingInformation); + $this->assertNotEmpty($paymentDetails); + $this->assertEquals($currentQuote->getGrandTotal(), $paymentDetails->getTotals()->getSubtotal()); + } + /** * Different variations for addresses test. * diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute.php new file mode 100644 index 0000000000000..ebe4ad76405ef --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute.php @@ -0,0 +1,96 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Model\Address; +use Magento\Customer\Model\Customer; +use Magento\Eav\Model\Config; +use Magento\Eav\Model\Entity\Type; +use Magento\Framework\Registry; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Customer\Model\Attribute; +use Magento\Eav\Model\Entity\Attribute\Set; + +$objectManager = Bootstrap::getObjectManager(); +/** @var $entityType Type */ +$entityType = $objectManager + ->create(Config::class) + ->getEntityType('customer'); + +/** @var $attributeSet Set */ +$attributeSet = Bootstrap::getObjectManager() + ->create(Set::class); + +$select = Bootstrap::getObjectManager()->create( + Attribute::class, + [ + 'data' => [ + 'frontend_input' => 'text', + 'frontend_label' => ['test_text_attribute'], + 'sort_order' => 1, + 'backend_type' => 'varchar', + 'is_user_defined' => 1, + 'is_system' => 0, + 'is_used_in_grid' => 1, + 'is_required' => '0', + 'is_visible' => 1, + 'used_in_forms' => [ + 'customer_address_edit', + 'adminhtml_customer_address' + ], + 'attribute_set_id' => $entityType->getDefaultAttributeSetId(), + 'attribute_group_id' => $attributeSet->getDefaultGroupId($entityType->getDefaultAttributeSetId()), + 'entity_type_id' => $entityType->getId(), + 'default_value' => '', + ], + ] +); +$select->setAttributeCode('test_text_attribute'); +$select->save(); + +$customer = $objectManager + ->create(Customer::class); +$customer->setWebsiteId(1) + ->setEntityId(1) + ->setEntityTypeId($entityType->getId()) + ->setAttributeSetId($entityType->getDefaultAttributeSetId()) + ->setEmail('JohnDoe@mail.com') + ->setPassword('password') + ->setGroupId(1) + ->setStoreId(1) + ->setIsActive(1) + ->setFirstname('John') + ->setLastname('Doe') + ->setGender(2) + ->setTestTextAttribute('123'); +$customer->isObjectNew(true); +// Create address +$address = $objectManager->create(Address::class); +// default_billing and default_shipping information would not be saved, it is needed only for simple check +$address->addData( + [ + 'firstname' => 'Charles', + 'lastname' => 'Alston', + 'street' => '3781 Neuport Lane', + 'city' => 'Panola', + 'country_id' => 'US', + 'region_id' => '51', + 'postcode' => '30058', + 'telephone' => '770-322-3514', + 'default_billing' => 1, + 'default_shipping' => 1, + ] +); +// Assign customer and address +$customer->addAddress($address); +$customer->save(); +// Mark last address as default billing and default shipping for current customer +$customer->setDefaultBilling($address->getId()); +$customer->setDefaultShipping($address->getId()); +$customer->save(); + +$objectManager->get(Registry::class)->unregister('_fixture/Magento_ImportExport_Customer'); +$objectManager->get(Registry::class)->register('_fixture/Magento_ImportExport_Customer', $customer); diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute_rollback.php new file mode 100644 index 0000000000000..3b276b77fbed5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address_with_custom_text_attribute_rollback.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Model\Customer; +use Magento\Framework\Registry; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Customer\Model\Attribute; + +/** @var Registry $registry */ +$registry = Bootstrap::getObjectManager()->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var $attribute Attribute */ +$attribute = Bootstrap::getObjectManager()->create( + Attribute::class +); +$attribute->loadByCode('customer', 'test_text_attribute'); +$attribute->delete(); + +/** @var Customer $customer */ +$customer = Bootstrap::getObjectManager() + ->create(Customer::class); +$customer->setWebsiteId(1); +$customer->loadByEmail('JohnDoe@mail.com'); +$customer->delete(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From e7bd3acc0e39f94d090bf5450581016d61f2c5e5 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi <stailx1@gmail.com> Date: Fri, 27 Nov 2020 08:36:42 +0100 Subject: [PATCH 122/346] add cast to int type in other places --- .../Model/Export/AdvancedPricing.php | 3 ++- .../Bundle/Model/ResourceModel/Selection.php | 3 ++- .../Indexer/Product/Price/AbstractAction.php | 13 ++++++----- .../Catalog/Model/ResourceModel/Attribute.php | 2 +- .../Catalog/Model/ResourceModel/Category.php | 3 ++- .../Catalog/Model/ResourceModel/Url.php | 22 ++++++++++++------- .../DataProvider/AttributeQuery.php | 2 +- .../Model/Indexer/Stock/AbstractAction.php | 4 ++-- .../Indexer/Stock/DefaultStock.php | 2 +- .../Model/ResourceModel/Stock/Status.php | 8 ++++--- .../CatalogRule/Model/ResourceModel/Rule.php | 2 +- .../Indexer/Stock/Configurable.php | 2 +- .../Product/Type/Configurable.php | 2 +- .../ResourceModel/Indexer/Stock/Grouped.php | 2 +- .../Product/Indexer/Price/Grouped.php | 2 +- .../Model/ResourceModel/Video.php | 3 ++- .../ResourceModel/Customer/Collection.php | 3 ++- 17 files changed, 47 insertions(+), 31 deletions(-) diff --git a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php index af43562984134..b63141b510b85 100644 --- a/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php +++ b/app/code/Magento/AdvancedPricingImportExport/Model/Export/AdvancedPricing.php @@ -486,7 +486,8 @@ private function fetchTierPrices(array $productIds): array ) ->where( 'ap.' . $productEntityLinkField . ' IN (?)', - $productIds + $productIds, + \Zend_Db::INT_TYPE ); if ($priceFromFilter !== null) { diff --git a/app/code/Magento/Bundle/Model/ResourceModel/Selection.php b/app/code/Magento/Bundle/Model/ResourceModel/Selection.php index ead687faff7bc..45018406277f9 100644 --- a/app/code/Magento/Bundle/Model/ResourceModel/Selection.php +++ b/app/code/Magento/Bundle/Model/ResourceModel/Selection.php @@ -145,7 +145,8 @@ public function getParentIdsByChild($childId) ['e.entity_id as parent_product_id'] )->where( $this->getMainTable() . '.product_id IN(?)', - $childId + $childId, + \Zend_Db::INT_TYPE ); return $connection->fetchCol($select); diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php index f3a4b322e29df..404fd27232b93 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php @@ -465,10 +465,11 @@ protected function _copyRelationIndexData($parentIds, $excludeIds = null) [] )->where( 'e.entity_id IN(?)', - $parentIds + $parentIds, + \Zend_Db::INT_TYPE ); if (!empty($excludeIds)) { - $select->where('child_id NOT IN(?)', $excludeIds); + $select->where('child_id NOT IN(?)', $excludeIds, \Zend_Db::INT_TYPE); } $children = $this->getConnection()->fetchCol($select); @@ -479,7 +480,8 @@ protected function _copyRelationIndexData($parentIds, $excludeIds = null) $this->getIndexTargetTableByDimension($dimensions) )->where( 'entity_id IN(?)', - $children + $children, + \Zend_Db::INT_TYPE ); $query = $select->insertFromSelect($this->_defaultIndexerResource->getIdxTable(), [], false); $this->getConnection()->query($query); @@ -578,13 +580,14 @@ private function getParentProductsTypes(array $productsIds) ['e.entity_id as parent_id', 'type_id'] )->where( 'l.child_id IN(?)', - $productsIds + $productsIds, + \Zend_Db::INT_TYPE ); $pairs = $this->getConnection()->fetchPairs($select); $byType = []; foreach ($pairs as $productId => $productType) { - $byType[$productType][$productId] = $productId; + $byType[$productType][$productId] = (int)$productId; } return $byType; diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php b/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php index 203126cf1fd8c..03f1edea0ea77 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Attribute.php @@ -101,7 +101,7 @@ protected function _clearUselessAttributeValues(\Magento\Framework\Model\Abstrac $attributeStoreIds = array_keys($this->_storeManager->getStores()); if (!empty($attributeStoreIds)) { $delCondition = [ - 'attribute_id = ?' => $object->getId(), + 'attribute_id = ?' => (int)$object->getId(), 'store_id IN(?)' => $attributeStoreIds, ]; $this->getConnection()->delete($object->getBackendTable(), $delCondition); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index e19286efc38c0..ed2df0f10ac3b 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -575,7 +575,8 @@ public function verifyIds(array $ids) 'entity_id' )->where( 'entity_id IN(?)', - $ids + $ids, + \Zend_Db::INT_TYPE ); return $this->getConnection()->fetchCol($select); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Url.php b/app/code/Magento/Catalog/Model/ResourceModel/Url.php index be95f088a2477..eceae322fbd8e 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Url.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Url.php @@ -204,7 +204,8 @@ protected function _getCategoryAttribute($attributeCode, $categoryIds, $storeId) ['value' => $attributeCode, 'entity_id' => 'entity_id'] )->where( 'entity_id IN(?)', - $categoryIds + $categoryIds, + \Zend_Db::INT_TYPE ); } elseif ($this->_categoryAttributes[$attributeCode]['is_global'] || $storeId == 0) { $select->from( @@ -216,7 +217,8 @@ protected function _getCategoryAttribute($attributeCode, $categoryIds, $storeId) ['value'] )->where( "t1.{$identifierFiled} IN(?)", - $categoryIds + $categoryIds, + \Zend_Db::INT_TYPE )->where( 'e.attribute_id = :attribute_id' )->where( @@ -245,7 +247,8 @@ protected function _getCategoryAttribute($attributeCode, $categoryIds, $storeId) 't1.attribute_id = :attribute_id' )->where( "e.entity_id IN(?)", - $categoryIds + $categoryIds, + \Zend_Db::INT_TYPE )->group('e.entity_id'); $bind['attribute_id'] = $this->_categoryAttributes[$attributeCode]['attribute_id']; @@ -308,7 +311,8 @@ public function _getProductAttribute($attributeCode, $productIds, $storeId) 0 )->where( 'entity_id IN(?)', - $productIds + $productIds, + \Zend_Db::INT_TYPE ); } else { $valueExpr = $connection->getCheckSql('t2.value_id > 0', 't2.value', 't1.value'); @@ -326,7 +330,8 @@ public function _getProductAttribute($attributeCode, $productIds, $storeId) 't1.attribute_id = :attribute_id' )->where( 't1.entity_id IN(?)', - $productIds + $productIds, + \Zend_Db::INT_TYPE ); $bind['store_id'] = $storeId; } @@ -430,7 +435,7 @@ protected function _getCategories($categoryIds, $storeId = null, $path = null) // Prepare variables for checking whether categories belong to store if ($path === null) { - $select->where('main_table.entity_id IN(?)', $categoryIds); + $select->where('main_table.entity_id IN(?)', $categoryIds, \Zend_Db::INT_TYPE); } else { // Ensure that path ends with '/', otherwise we can get wrong results - e.g. $path = '1/2' will get '1/20' if (substr($path, -1) != '/') { @@ -569,7 +574,7 @@ protected function _getProducts($productIds, $storeId, $entityId, &$lastEntityId $this->_productLimit ); if ($productIds !== null) { - $select->where('e.entity_id IN(?)', $productIds); + $select->where('e.entity_id IN(?)', $productIds, \Zend_Db::INT_TYPE); } $rowSet = $connection->fetchAll($select, $bind); @@ -591,7 +596,8 @@ protected function _getProducts($productIds, $storeId, $entityId, &$lastEntityId ['product_id', 'category_id'] )->where( 'product_id IN(?)', - array_keys($products) + array_keys($products), + \Zend_Db::INT_TYPE ); $categories = $connection->fetchAll($select); foreach ($categories as $category) { diff --git a/app/code/Magento/CatalogGraphQl/DataProvider/AttributeQuery.php b/app/code/Magento/CatalogGraphQl/DataProvider/AttributeQuery.php index b0f085932bb8e..201c70913ca39 100644 --- a/app/code/Magento/CatalogGraphQl/DataProvider/AttributeQuery.php +++ b/app/code/Magento/CatalogGraphQl/DataProvider/AttributeQuery.php @@ -148,7 +148,7 @@ private function getAttributesFromEntityTable( ): Select { $select = $connection->select() ->from(['e' => $entityTableName], $entityTableAttributes) - ->where('e.entity_id IN (?)', $entityIds); + ->where('e.entity_id IN (?)', $entityIds, \Zend_Db::INT_TYPE); return $select; } diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php index 4ea6b6bcfde9a..0b5f248331bfd 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php @@ -167,7 +167,7 @@ public function getRelationsByChild($childIds) )->join( ['relation' => $this->_getTable('catalog_product_relation')], 'relation.parent_id = cpe.' . $linkField - )->where('child_id IN(?)', $childIds); + )->where('child_id IN(?)', $childIds, \Zend_Db::INT_TYPE); return $connection->fetchCol($select); } @@ -262,7 +262,7 @@ private function doReindex($productIds = []) // retrieve product types by processIds $select = $connection->select() ->from($this->_getTable('catalog_product_entity'), ['entity_id', 'type_id']) - ->where('entity_id IN(?)', $productIds); + ->where('entity_id IN(?)', $productIds, \Zend_Db::INT_TYPE); $pairs = $connection->fetchPairs($select); $byType = []; diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php index c151e5897abd5..dec18044b699e 100644 --- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php +++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Indexer/Stock/DefaultStock.php @@ -261,7 +261,7 @@ protected function _getStockStatusSelect($entityIds = null, $usePrimaryTable = f $select->columns(['status' => $this->getStatusExpression($connection, true)]); if ($entityIds !== null) { - $select->where('e.entity_id IN(?)', $entityIds); + $select->where('e.entity_id IN(?)', $entityIds, \Zend_Db::INT_TYPE); } return $select; diff --git a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php index 02e443d09b228..afb7d51335df8 100644 --- a/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php +++ b/app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Status.php @@ -153,7 +153,7 @@ public function getProductsStockStatuses($productIds, $websiteId, $stockId = Sto $select = $this->getConnection()->select() ->from($this->getMainTable(), ['product_id', 'stock_status']) - ->where('product_id IN(?)', $productIds) + ->where('product_id IN(?)', $productIds, \Zend_Db::INT_TYPE) ->where('stock_id=?', (int) $stockId) ->where('website_id=?', (int) $websiteId); return $this->getConnection()->fetchPairs($select); @@ -190,7 +190,8 @@ public function getProductsType($productIds) ['entity_id', 'type_id'] )->where( 'entity_id IN(?)', - $productIds + $productIds, + \Zend_Db::INT_TYPE ); return $this->getConnection()->fetchPairs($select); } @@ -360,7 +361,8 @@ public function getProductStatus($productIds, $storeId = null) $attribute->getAttributeId() )->where( "t1.{$linkField} IN(?)", - $productIds + $productIds, + \Zend_Db::INT_TYPE ); $rows = $connection->fetchPairs($select); diff --git a/app/code/Magento/CatalogRule/Model/ResourceModel/Rule.php b/app/code/Magento/CatalogRule/Model/ResourceModel/Rule.php index 662cdede84ede..dd4f3306b8603 100644 --- a/app/code/Magento/CatalogRule/Model/ResourceModel/Rule.php +++ b/app/code/Magento/CatalogRule/Model/ResourceModel/Rule.php @@ -187,7 +187,7 @@ public function getRulePrices(\DateTimeInterface $date, $websiteId, $customerGro ->where('rule_date = ?', $date->format('Y-m-d')) ->where('website_id = ?', $websiteId) ->where('customer_group_id = ?', $customerGroupId) - ->where('product_id IN(?)', $productIds); + ->where('product_id IN(?)', $productIds, \Zend_Db::INT_TYPE); return $connection->fetchPairs($select); } diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php index 39fcdf86fdcf4..29c4812cc7b96 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Indexer/Stock/Configurable.php @@ -101,7 +101,7 @@ protected function _getStockStatusSelect($entityIds = null, $usePrimaryTable = f $select->columns(['status' => $stockStatusExpr]); if ($entityIds !== null) { - $select->where('e.entity_id IN(?)', $entityIds); + $select->where('e.entity_id IN(?)', $entityIds, \Zend_Db::INT_TYPE); } return $select; diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php index 9d779d9704c29..0dd38062e5a65 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Type/Configurable.php @@ -203,7 +203,7 @@ public function getParentIdsByChild($childId) ['e' => $this->getTable('catalog_product_entity')], 'e.' . $this->optionProvider->getProductEntityLinkField() . ' = l.parent_id', ['e.entity_id'] - )->where('l.product_id IN(?)', $childId); + )->where('l.product_id IN(?)', $childId, \Zend_Db::INT_TYPE); $parentIds = $this->getConnection()->fetchCol($select); return $parentIds; diff --git a/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php b/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php index 9d29b02f68bf1..b2a8a361564e0 100644 --- a/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/ResourceModel/Indexer/Stock/Grouped.php @@ -94,7 +94,7 @@ protected function _getStockStatusSelect($entityIds = null, $usePrimaryTable = f $select->columns(['status' => $stockStatusExpr]); if ($entityIds !== null) { - $select->where('e.entity_id IN(?)', $entityIds); + $select->where('e.entity_id IN(?)', $entityIds, \Zend_Db::INT_TYPE); } return $select; diff --git a/app/code/Magento/GroupedProduct/Model/ResourceModel/Product/Indexer/Price/Grouped.php b/app/code/Magento/GroupedProduct/Model/ResourceModel/Product/Indexer/Price/Grouped.php index c5f0316feb126..4c24cdb752d3c 100644 --- a/app/code/Magento/GroupedProduct/Model/ResourceModel/Product/Indexer/Price/Grouped.php +++ b/app/code/Magento/GroupedProduct/Model/ResourceModel/Product/Indexer/Price/Grouped.php @@ -166,7 +166,7 @@ private function prepareGroupedProductPriceDataSelect(array $dimensions, array $ ); if ($entityIds !== null) { - $select->where('e.entity_id IN(?)', $entityIds); + $select->where('e.entity_id IN(?)', $entityIds, \Zend_Db::INT_TYPE); } return $select; diff --git a/app/code/Magento/ProductVideo/Model/ResourceModel/Video.php b/app/code/Magento/ProductVideo/Model/ResourceModel/Video.php index 68b593f335797..42fdf8265ee83 100644 --- a/app/code/Magento/ProductVideo/Model/ResourceModel/Video.php +++ b/app/code/Magento/ProductVideo/Model/ResourceModel/Video.php @@ -39,7 +39,8 @@ public function loadByIds(array $ids) $this->getMainTable() )->where( 'value_id IN(?)', - $ids + $ids, + \Zend_Db::INT_TYPE ); return $this->getConnection()->fetchAll($select); diff --git a/app/code/Magento/Reports/Model/ResourceModel/Customer/Collection.php b/app/code/Magento/Reports/Model/ResourceModel/Customer/Collection.php index b6e55af96f4c1..a346ad4ede29b 100644 --- a/app/code/Magento/Reports/Model/ResourceModel/Customer/Collection.php +++ b/app/code/Magento/Reports/Model/ResourceModel/Customer/Collection.php @@ -213,7 +213,8 @@ protected function _addOrdersStatistics() \Magento\Sales\Model\Order::STATE_CANCELED )->where( 'orders.customer_id IN(?)', - $customerIds + $customerIds, + \Zend_Db::INT_TYPE )->group( 'orders.customer_id' ); From 9bd13e403a7d21bea3e0c819cd7f546de153f815 Mon Sep 17 00:00:00 2001 From: engcom-Echo <engcom-vendorworker-echo@adobe.com> Date: Fri, 27 Nov 2020 12:58:01 +0200 Subject: [PATCH 123/346] MC-37807: Link to a file of a Product with Customizable Option(File) is not available throughout a multishipping checkout process --- .../templates/checkout/item/default.phtml | 15 ++- .../Block/Checkout/OverviewTest.php | 91 ++++++++++++++----- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml b/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml index 5d7f06475af28..d5ef7e3d5c448 100644 --- a/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml +++ b/app/code/Magento/Multishipping/view/frontend/templates/checkout/item/default.phtml @@ -6,18 +6,23 @@ // phpcs:disable Magento2.Files.LineLength ?> -<strong class="product name product-item-name"><a href="<?= $block->escapeUrl($block->getProductUrl()) ?>"><?= $block->escapeHtml($block->getProductName()) ?></a></strong> +<?php +/** @var \Magento\Checkout\Block\Cart\Item\Renderer\ $block */ +/** @var \Magento\Framework\Escaper $escaper */ +?> + +<strong class="product name product-item-name"><a href="<?= $escaper->escapeUrl($block->getProductUrl()) ?>"><?= $escaper->escapeHtml($block->getProductName()) ?></a></strong> <?php if ($_options = $block->getOptionList()) : ?> <dl class="item-options"> <?php foreach ($_options as $_option) : ?> <?php $_formatedOptionValue = $block->getFormatedOptionValue($_option) ?> - <dt><?= $block->escapeHtml($_option['label']) ?></dt> + <dt><?= $escaper->escapeHtml($_option['label']) ?></dt> <dd<?= (isset($_formatedOptionValue['full_view']) ? ' class="tooltip wrapper"' : '') ?>> - <?= $block->escapeHtml($_formatedOptionValue['value'], ['span', 'a']) ?> + <?= $escaper->escapeHtml($_formatedOptionValue['value'], ['span', 'a']) ?> <?php if (isset($_formatedOptionValue['full_view'])) : ?> <dl class="item options tooltip content"> - <dt><?= $block->escapeHtml($_option['label']) ?></dt> - <dd><?= $block->escapeHtml($_formatedOptionValue['full_view'], ['span']) ?></dd> + <dt><?= $escaper->escapeHtml($_option['label']) ?></dt> + <dd><?= $escaper->escapeHtml($_formatedOptionValue['full_view'], ['span']) ?></dd> </dl> <?php endif; ?> </dd> diff --git a/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php b/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php index 5009f210404d0..f4829cb614234 100644 --- a/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php +++ b/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php @@ -6,28 +6,55 @@ namespace Magento\Multishipping\Block\Checkout; +use Magento\Catalog\Model\Product; +use Magento\Checkout\Block\Cart\Item\Renderer; +use Magento\Framework\App\Area; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\Element\RendererList; +use Magento\Framework\View\LayoutInterface; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Item; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; +use PHPUnit\Framework\TestCase; + /** - * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * Verify default items template */ -class OverviewTest extends \PHPUnit\Framework\TestCase +class OverviewTest extends TestCase { /** - * @var \Magento\Multishipping\Block\Checkout\Overview + * @var Overview + */ + protected $block; + + /** + * @var ObjectManagerInterface */ - protected $_block; + protected $objectManager; /** - * @var \Magento\Framework\ObjectManagerInterface + * @var Quote */ - protected $_objectManager; + private $quote; + + /** + * @var Product + */ + private $product; + + /** + * @var Item + */ + private $item; protected function setUp(): void { - \Magento\TestFramework\Helper\Bootstrap::getInstance()->loadArea(\Magento\Framework\App\Area::AREA_FRONTEND); - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->_block = $this->_objectManager->get(\Magento\Framework\View\LayoutInterface::class) + Bootstrap::getInstance()->loadArea(Area::AREA_FRONTEND); + $this->objectManager = Bootstrap::getObjectManager(); + $this->block = $this->objectManager->get(LayoutInterface::class) ->createBlock( - \Magento\Multishipping\Block\Checkout\Overview::class, + Overview::class, 'checkout_overview', [ 'data' => [ @@ -37,33 +64,49 @@ protected function setUp(): void ] ); - $this->_block->addChild('renderer.list', \Magento\Framework\View\Element\RendererList::class); - $this->_block->getChildBlock( + $this->block->addChild('renderer.list', RendererList::class); + $this->block->getChildBlock( 'renderer.list' )->addChild( 'default', - \Magento\Checkout\Block\Cart\Item\Renderer::class, + Renderer::class, ['template' => 'cart/item/default.phtml'] ); + $this->quote = $this->objectManager->get(Quote::class); + $this->product = $this->objectManager->get(Product::class); + $this->item = $this->objectManager->get(Item::class); } + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + */ public function testGetRowItemHtml() { - /** @var $item \Magento\Quote\Model\Quote\Item */ - $item = $this->_objectManager->create(\Magento\Quote\Model\Quote\Item::class); - /** @var $product \Magento\Catalog\Model\Product */ - $product = $this->_objectManager->create(\Magento\Catalog\Model\Product::class); - $product->load(1); - $item->setProduct($product); - /** @var $quote \Magento\Quote\Model\Quote */ - $quote = $this->_objectManager->create(\Magento\Quote\Model\Quote::class); - $item->setQuote($quote); + $product = $this->product->load('1'); + $item = $this->item->setProduct($product); + $item->setQuote($this->quote); // assure that default renderer was obtained $this->assertEquals( 1, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath( + Xpath::getElementsCountForXpath( '//*[contains(@class,"product") and contains(@class,"name")]/a', - $this->_block->getRowItemHtml($item) + $this->block->getRowItemHtml($item) + ) + ); + } + + /** + * @magentoDataFixture Magento/Checkout/_files/customer_quote_with_items_simple_product_options.php + */ + public function testLinkOptionalProductFileItemHtml() + { + $quote = $this->quote->load('customer_quote_product_custom_options', 'reserved_order_id'); + $item = current($quote->getAllItems()); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + '//dd/a[contains(text(), "test.jpg")]', + $this->block->getRowItemHtml($item) ) ); } From 3b0e854a0e9a7dd18c135259d14bfd50a5e7dd5f Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Fri, 27 Nov 2020 13:33:34 +0200 Subject: [PATCH 124/346] fix action group, revert i18n changes --- .../AdminGoToCreditmemoViewActionGroup.xml | 2 +- ...tmemoViewPageWithWrongCreditmemoIdTest.xml | 6 +- app/code/Magento/Sales/i18n/en_US.csv | 1280 ++++++++--------- 3 files changed, 642 insertions(+), 646 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml index d417a6c5ed314..08d02fe2b7bb1 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminGoToCreditmemoViewActionGroup.xml @@ -16,7 +16,7 @@ <argument name="identifier" type="string"/> </arguments> - <amOnPage url="{{AdminCreditMemoViewPage.url}}/{{identifier}}" stepKey="amOnCreditmemoViewPage"/> + <amOnPage url="{{AdminCreditMemoViewPage.url}}{{identifier}}" stepKey="amOnCreditmemoViewPage"/> <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml index cf7f61aa12a20..4436aab59874a 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml @@ -16,11 +16,9 @@ <severity value="MAJOR"/> <group value="sales"/> </annotations> - <before> <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> </before> - <after> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> @@ -30,9 +28,7 @@ </actionGroup> <waitForPageLoad stepKey="waitForPageLoad"/> - <seeInCurrentUrl url="{{AdminCreditMemosGridPage.url}}" stepKey="redirectToCreditMemosGridPage"/> - - <actionGroup ref="AssertAdminPageIs404ActionGroup" stepKey="see404PageOnAdmin"/> + <see selector="{{AdminMessagesSection.error}}" userInput='This creditmemo no longer exists.' stepKey="seeErrorMessage"/> </test> </tests> diff --git a/app/code/Magento/Sales/i18n/en_US.csv b/app/code/Magento/Sales/i18n/en_US.csv index c429a10411af4..03589afb1cd19 100644 --- a/app/code/Magento/Sales/i18n/en_US.csv +++ b/app/code/Magento/Sales/i18n/en_US.csv @@ -1,344 +1,344 @@ -Credit Memos,Credit Memos +"Credit Memos","Credit Memos" Orders,Orders Invoices,Invoices -We can't get the order instance right now.,We can't get the order instance right now. -Create New Order,Create New Order -Save Order Address,Save Order Address +"We can't get the order instance right now.","We can't get the order instance right now." +"Create New Order","Create New Order" +"Save Order Address","Save Order Address" Shipping,Shipping Billing,Billing -Edit Order %1 %2 Address,Edit Order %1 %2 Address -Order Address Information,Order Address Information -Please correct the parent block for this block.,Please correct the parent block for this block. -Submit Comment,Submit Comment -Submit Order,Submit Order -Are you sure you want to cancel this order?,Are you sure you want to cancel this order? +"Edit Order %1 %2 Address","Edit Order %1 %2 Address" +"Order Address Information","Order Address Information" +"Please correct the parent block for this block.","Please correct the parent block for this block." +"Submit Comment","Submit Comment" +"Submit Order","Submit Order" +"Are you sure you want to cancel this order?","Are you sure you want to cancel this order?" Cancel,Cancel -Billing Address,Billing Address -Payment Method,Payment Method -Order Comment,Order Comment +"Billing Address","Billing Address" +"Payment Method","Payment Method" +"Order Comment","Order Comment" Coupons,Coupons -Please select a customer,Please select a customer -Create New Customer,Create New Customer -Account Information,Account Information +"Please select a customer","Please select a customer" +"Create New Customer","Create New Customer" +"Account Information","Account Information" From,From To,To Message,Message -Edit Order #%1,Edit Order #%1 -Create New Order for %1 in %2,Create New Order for %1 in %2 -Create New Order in %1,Create New Order in %1 -Create New Order for %1,Create New Order for %1 -Create New Order for New Customer,Create New Order for New Customer -Items Ordered,Items Ordered -This product is disabled.,This product is disabled. -Buy %1 for price %2,Buy %1 for price %2 -Item ordered qty,Item ordered qty -%1 with %2 discount each,%1 with %2 discount each -%1 for %2,%1 for %2 -* - Enter custom price including tax,* - Enter custom price including tax -* - Enter custom price excluding tax,* - Enter custom price excluding tax +"Edit Order #%1","Edit Order #%1" +"Create New Order for %1 in %2","Create New Order for %1 in %2" +"Create New Order in %1","Create New Order in %1" +"Create New Order for %1","Create New Order for %1" +"Create New Order for New Customer","Create New Order for New Customer" +"Items Ordered","Items Ordered" +"This product is disabled.","This product is disabled." +"Buy %1 for price %2","Buy %1 for price %2" +"Item ordered qty","Item ordered qty" +"%1 with %2 discount each","%1 with %2 discount each" +"%1 for %2","%1 for %2" +"* - Enter custom price including tax","* - Enter custom price including tax" +"* - Enter custom price excluding tax","* - Enter custom price excluding tax" Configure,Configure -This product does not have any configurable options,This product does not have any configurable options -Newsletter Subscription,Newsletter Subscription -Please select products,Please select products -Add Selected Product(s) to Order,Add Selected Product(s) to Order +"This product does not have any configurable options","This product does not have any configurable options" +"Newsletter Subscription","Newsletter Subscription" +"Please select products","Please select products" +"Add Selected Product(s) to Order","Add Selected Product(s) to Order" ID,ID Product,Product SKU,SKU Price,Price Select,Select Quantity,Quantity -Shipping Address,Shipping Address -Shipping Method,Shipping Method -Update Changes,Update Changes -Shopping Cart,Shopping Cart -Are you sure you want to delete all items from shopping cart?,Are you sure you want to delete all items from shopping cart? -Clear Shopping Cart,Clear Shopping Cart -Products in Comparison List,Products in Comparison List -Recently Compared Products,Recently Compared Products -Recently Viewed Products,Recently Viewed Products -Last Ordered Items,Last Ordered Items -Recently Viewed,Recently Viewed -Wish List,Wish List -Please select a store,Please select a store -Order Totals,Order Totals -Shipping Incl. Tax (%1),Shipping Incl. Tax (%1) -Shipping Excl. Tax (%1),Shipping Excl. Tax (%1) -New Credit Memo for Invoice #%1,New Credit Memo for Invoice #%1 -New Credit Memo for Order #%1,New Credit Memo for Order #%1 -Refund Shipping (Incl. Tax),Refund Shipping (Incl. Tax) -Refund Shipping (Excl. Tax),Refund Shipping (Excl. Tax) -Refund Shipping,Refund Shipping -Update Qty's,Update Qty's +"Shipping Address","Shipping Address" +"Shipping Method","Shipping Method" +"Update Changes","Update Changes" +"Shopping Cart","Shopping Cart" +"Are you sure you want to delete all items from shopping cart?","Are you sure you want to delete all items from shopping cart?" +"Clear Shopping Cart","Clear Shopping Cart" +"Products in Comparison List","Products in Comparison List" +"Recently Compared Products","Recently Compared Products" +"Recently Viewed Products","Recently Viewed Products" +"Last Ordered Items","Last Ordered Items" +"Recently Viewed","Recently Viewed" +"Wish List","Wish List" +"Please select a store","Please select a store" +"Order Totals","Order Totals" +"Shipping Incl. Tax (%1)","Shipping Incl. Tax (%1)" +"Shipping Excl. Tax (%1)","Shipping Excl. Tax (%1)" +"New Credit Memo for Invoice #%1","New Credit Memo for Invoice #%1" +"New Credit Memo for Order #%1","New Credit Memo for Order #%1" +"Refund Shipping (Incl. Tax)","Refund Shipping (Incl. Tax)" +"Refund Shipping (Excl. Tax)","Refund Shipping (Excl. Tax)" +"Refund Shipping","Refund Shipping" +"Update Qty's","Update Qty's" Refund,Refund -Refund Offline,Refund Offline -Paid Amount,Paid Amount -Refund Amount,Refund Amount -Shipping Amount,Shipping Amount -Shipping Refund,Shipping Refund -Order Grand Total,Order Grand Total -Adjustment Refund,Adjustment Refund -Adjustment Fee,Adjustment Fee -Send Email,Send Email -Are you sure you want to send a credit memo email to customer?,Are you sure you want to send a credit memo email to customer? +"Refund Offline","Refund Offline" +"Paid Amount","Paid Amount" +"Refund Amount","Refund Amount" +"Shipping Amount","Shipping Amount" +"Shipping Refund","Shipping Refund" +"Order Grand Total","Order Grand Total" +"Adjustment Refund","Adjustment Refund" +"Adjustment Fee","Adjustment Fee" +"Send Email","Send Email" +"Are you sure you want to send a credit memo email to customer?","Are you sure you want to send a credit memo email to customer?" Void,Void Print,Print -The credit memo email was sent.,The credit memo email was sent. -The credit memo email wasn't sent.,The credit memo email wasn't sent. -Credit Memo #%1 | %3 | %2 (%4),Credit Memo #%1 | %3 | %2 (%4) -Total Refund,Total Refund -New Invoice and Shipment for Order #%1,New Invoice and Shipment for Order #%1 -New Invoice for Order #%1,New Invoice for Order #%1 -Submit Invoice and Shipment,Submit Invoice and Shipment -Submit Invoice,Submit Invoice -Are you sure you want to send an invoice email to customer?,Are you sure you want to send an invoice email to customer? -Credit Memo,Credit Memo +"The credit memo email was sent.","The credit memo email was sent." +"The credit memo email wasn't sent.","The credit memo email wasn't sent." +"Credit Memo #%1 | %3 | %2 (%4)","Credit Memo #%1 | %3 | %2 (%4)" +"Total Refund","Total Refund" +"New Invoice and Shipment for Order #%1","New Invoice and Shipment for Order #%1" +"New Invoice for Order #%1","New Invoice for Order #%1" +"Submit Invoice and Shipment","Submit Invoice and Shipment" +"Submit Invoice","Submit Invoice" +"Are you sure you want to send an invoice email to customer?","Are you sure you want to send an invoice email to customer?" +"Credit Memo","Credit Memo" Capture,Capture -The invoice email was sent.,The invoice email was sent. -The invoice email wasn't sent.,The invoice email wasn't sent. -Invoice #%1 | %2 | %4 (%3),Invoice #%1 | %2 | %4 (%3) -Invalid parent block for this block,Invalid parent block for this block -Order Statuses,Order Statuses -Create New Status,Create New Status -Assign Status to State,Assign Status to State -Save Status Assignment,Save Status Assignment -Assign Order Status to State,Assign Order Status to State -Assignment Information,Assignment Information -Order Status,Order Status -Order State,Order State -Use Order Status As Default,Use Order Status As Default -Visible On Storefront,Visible On Storefront -Edit Order Status,Edit Order Status -Save Status,Save Status -New Order Status,New Order Status -Order Status Information,Order Status Information -Status Code,Status Code -Status Label,Status Label -Store View Specific Labels,Store View Specific Labels -Total Paid,Total Paid -Total Refunded,Total Refunded -Total Due,Total Due -Total Canceled,Total Canceled +"The invoice email was sent.","The invoice email was sent." +"The invoice email wasn't sent.","The invoice email wasn't sent." +"Invoice #%1 | %2 | %4 (%3)","Invoice #%1 | %2 | %4 (%3)" +"Invalid parent block for this block","Invalid parent block for this block" +"Order Statuses","Order Statuses" +"Create New Status","Create New Status" +"Assign Status to State","Assign Status to State" +"Save Status Assignment","Save Status Assignment" +"Assign Order Status to State","Assign Order Status to State" +"Assignment Information","Assignment Information" +"Order Status","Order Status" +"Order State","Order State" +"Use Order Status As Default","Use Order Status As Default" +"Visible On Storefront","Visible On Storefront" +"Edit Order Status","Edit Order Status" +"Save Status","Save Status" +"New Order Status","New Order Status" +"Order Status Information","Order Status Information" +"Status Code","Status Code" +"Status Label","Status Label" +"Store View Specific Labels","Store View Specific Labels" +"Total Paid","Total Paid" +"Total Refunded","Total Refunded" +"Total Due","Total Due" +"Total Canceled","Total Canceled" Edit,Edit -Are you sure you want to send an order email to customer?,Are you sure you want to send an order email to customer? +"Are you sure you want to send an order email to customer?","Are you sure you want to send an order email to customer?" "This will create an offline refund. To create an online refund, open an invoice and create credit memo for it. Do you want to continue?","This will create an offline refund. To create an online refund, open an invoice and create credit memo for it. Do you want to continue?" -Are you sure you want to void the payment?,Are you sure you want to void the payment? +"Are you sure you want to void the payment?","Are you sure you want to void the payment?" Hold,Hold hold,hold Unhold,Unhold unhold,unhold -Are you sure you want to accept this payment?,Are you sure you want to accept this payment? -Accept Payment,Accept Payment -Are you sure you want to deny this payment?,Are you sure you want to deny this payment? -Deny Payment,Deny Payment -Get Payment Update,Get Payment Update -Invoice and Ship,Invoice and Ship +"Are you sure you want to accept this payment?","Are you sure you want to accept this payment?" +"Accept Payment","Accept Payment" +"Are you sure you want to deny this payment?","Are you sure you want to deny this payment?" +"Deny Payment","Deny Payment" +"Get Payment Update","Get Payment Update" +"Invoice and Ship","Invoice and Ship" Invoice,Invoice Ship,Ship Reorder,Reorder -Order # %1 %2 | %3,Order # %1 %2 | %3 +"Order # %1 %2 | %3","Order # %1 %2 | %3" "This order contains (%1) items and therefore cannot be edited through the admin interface. If you wish to continue editing, the (%2) items will be removed, the order will be canceled and a new order will be placed.","This order contains (%1) items and therefore cannot be edited through the admin interface. If you wish to continue editing, the (%2) items will be removed, the order will be canceled and a new order will be placed." -Are you sure? This order will be canceled and a new one will be created instead.,Are you sure? This order will be canceled and a new one will be created instead. -Save Gift Message,Save Gift Message - [deleted], [deleted] -Order Credit Memos,Order Credit Memos -Credit memo #%1 created,Credit memo #%1 created -Credit memo #%1 comment added,Credit memo #%1 comment added -Shipment #%1 created,Shipment #%1 created -Shipment #%1 comment added,Shipment #%1 comment added -Invoice #%1 created,Invoice #%1 created -Invoice #%1 comment added,Invoice #%1 comment added -Tracking number %1 for %2 assigned,Tracking number %1 for %2 assigned -Comments History,Comments History -Order History,Order History +"Are you sure? This order will be canceled and a new one will be created instead.","Are you sure? This order will be canceled and a new one will be created instead." +"Save Gift Message","Save Gift Message" +" [deleted]"," [deleted]" +"Order Credit Memos","Order Credit Memos" +"Credit memo #%1 created","Credit memo #%1 created" +"Credit memo #%1 comment added","Credit memo #%1 comment added" +"Shipment #%1 created","Shipment #%1 created" +"Shipment #%1 comment added","Shipment #%1 comment added" +"Invoice #%1 created","Invoice #%1 created" +"Invoice #%1 comment added","Invoice #%1 comment added" +"Tracking number %1 for %2 assigned","Tracking number %1 for %2 assigned" +"Comments History","Comments History" +"Order History","Order History" Information,Information -Order Information,Order Information -Order Invoices,Order Invoices +"Order Information","Order Information" +"Order Invoices","Order Invoices" Shipments,Shipments -Order Shipments,Order Shipments +"Order Shipments","Order Shipments" Transactions,Transactions -Order View,Order View +"Order View","Order View" Any,Any Specified,Specified -Applies to Any of the Specified Order Statuses except canceled orders,Applies to Any of the Specified Order Statuses except canceled orders -Cart Price Rule,Cart Price Rule +"Applies to Any of the Specified Order Statuses except canceled orders","Applies to Any of the Specified Order Statuses except canceled orders" +"Cart Price Rule","Cart Price Rule" Yes,Yes No,No -Show Actual Values,Show Actual Values -New Order RSS,New Order RSS +"Show Actual Values","Show Actual Values" +"New Order RSS","New Order RSS" Subtotal,Subtotal -Shipping & Handling,Shipping & Handling -Discount (%1),Discount (%1) +"Shipping & Handling","Shipping & Handling" +"Discount (%1)","Discount (%1)" Discount,Discount -Grand Total,Grand Total +"Grand Total","Grand Total" Back,Back Fetch,Fetch -Transaction # %1 | %2,Transaction # %1 | %2 +"Transaction # %1 | %2","Transaction # %1 | %2" N/A,N/A Key,Key Value,Value -We found an invalid entity model.,We found an invalid entity model. -Order # %1,Order # %1 -Back to My Orders,Back to My Orders -View Another Order,View Another Order -About Your Refund,About Your Refund -My Orders,My Orders -Subscribe to Order Status,Subscribe to Order Status -About Your Invoice,About Your Invoice -Print Order # %1,Print Order # %1 -Grand Total to be Charged,Grand Total to be Charged +"We found an invalid entity model.","We found an invalid entity model." +"Order # %1","Order # %1" +"Back to My Orders","Back to My Orders" +"View Another Order","View Another Order" +"About Your Refund","About Your Refund" +"My Orders","My Orders" +"Subscribe to Order Status","Subscribe to Order Status" +"About Your Invoice","About Your Invoice" +"Print Order # %1","Print Order # %1" +"Grand Total to be Charged","Grand Total to be Charged" Unassign,Unassign -We can't add this item to your shopping cart right now.,We can't add this item to your shopping cart right now. -You sent the message.,You sent the message. +"We can't add this item to your shopping cart right now.","We can't add this item to your shopping cart right now." +"You sent the message.","You sent the message." Sales,Sales -Invoice capturing error,Invoice capturing error -This order no longer exists.,This order no longer exists. -Please enter a comment.,Please enter a comment. -We cannot add order history.,We cannot add order history. -You updated the order address.,You updated the order address. -We can't update the order address right now.,We can't update the order address right now. -You have not canceled the item.,You have not canceled the item. -You canceled the order.,You canceled the order. +"Invoice capturing error","Invoice capturing error" +"This order no longer exists.","This order no longer exists." +"Please enter a comment.","Please enter a comment." +"We cannot add order history.","We cannot add order history." +"You updated the order address.","You updated the order address." +"We can't update the order address right now.","We can't update the order address right now." +"You have not canceled the item.","You have not canceled the item." +"You canceled the order.","You canceled the order." """%1"" coupon code was not applied. Do not apply discount is selected for item(s)","""%1"" coupon code was not applied. Do not apply discount is selected for item(s)" """%1"" coupon code is not valid.","""%1"" coupon code is not valid." -The coupon code has been accepted.,The coupon code has been accepted. -Quote item id is not received.,Quote item id is not received. -Quote item is not loaded.,Quote item is not loaded. -New Order,New Order -You created the order.,You created the order. -Order saving error: %1,Order saving error: %1 -Cannot add new comment.,Cannot add new comment. -The credit memo has been canceled.,The credit memo has been canceled. -Credit memo has not been canceled.,Credit memo has not been canceled. -New Memo for #%1,New Memo for #%1 -New Memo,New Memo -The credit memo's total must be positive.,The credit memo's total must be positive. -Cannot create online refund for Refund to Store Credit.,Cannot create online refund for Refund to Store Credit. -You created the credit memo.,You created the credit memo. -We can't save the credit memo right now.,We can't save the credit memo right now. -We can't update the item's quantity right now.,We can't update the item's quantity right now. -View Memo for #%1,View Memo for #%1 -View Memo,View Memo -You voided the credit memo.,You voided the credit memo. -We can't void the credit memo.,We can't void the credit memo. -The order no longer exists.,The order no longer exists. -We can't create credit memo for the order.,We can't create credit memo for the order. -Edit Order,Edit Order -You sent the order email.,You sent the order email. -We can't send the email order right now.,We can't send the email order right now. -You have not put the order on hold.,You have not put the order on hold. -You put the order on hold.,You put the order on hold. -You canceled the invoice.,You canceled the invoice. -Invoice canceling error,Invoice canceling error -The invoice has been captured.,The invoice has been captured. -The order does not allow an invoice to be created.,The order does not allow an invoice to be created. -You can't create an invoice without products.,You can't create an invoice without products. -New Invoice,New Invoice -We can't save the invoice right now.,We can't save the invoice right now. -You created the invoice and shipment.,You created the invoice and shipment. -The invoice has been created.,The invoice has been created. -We can't send the invoice email right now.,We can't send the invoice email right now. -We can't send the shipment right now.,We can't send the shipment right now. -Cannot update item quantity.,Cannot update item quantity. -The invoice has been voided.,The invoice has been voided. -Invoice voiding error,Invoice voiding error -%1 order(s) cannot be canceled.,%1 order(s) cannot be canceled. -You cannot cancel the order(s).,You cannot cancel the order(s). -We canceled %1 order(s).,We canceled %1 order(s). -%1 order(s) were not put on hold.,%1 order(s) were not put on hold. -No order(s) were put on hold.,No order(s) were put on hold. -You have put %1 order(s) on hold.,You have put %1 order(s) on hold. -%1 order(s) were not released from on hold status.,%1 order(s) were not released from on hold status. -No order(s) were released from on hold status.,No order(s) were released from on hold status. -%1 order(s) have been released from on hold status.,%1 order(s) have been released from on hold status. -There are no printable documents related to selected orders.,There are no printable documents related to selected orders. -The payment has been accepted.,The payment has been accepted. -The payment has been denied.,The payment has been denied. -Transaction has been approved.,Transaction has been approved. -Transaction has been voided/declined.,Transaction has been voided/declined. -There is no update for the transaction.,There is no update for the transaction. -We can't update the payment right now.,We can't update the payment right now. -You assigned the order status.,You assigned the order status. -Something went wrong while assigning the order status.,Something went wrong while assigning the order status. -We can't find this order status.,We can't find this order status. -Create New Order Status,Create New Order Status -We found another order status with the same order status code.,We found another order status with the same order status code. -You saved the order status.,You saved the order status. -We can't add the order status right now.,We can't add the order status right now. -You have unassigned the order status.,You have unassigned the order status. -Something went wrong while unassigning the order.,Something went wrong while unassigning the order. -Can't unhold order.,Can't unhold order. -You released the order from holding status.,You released the order from holding status. -The order was not on hold.,The order was not on hold. -Exception occurred during order load,Exception occurred during order load -Something went wrong while saving the gift message.,Something went wrong while saving the gift message. -You saved the gift card message.,You saved the gift card message. -The payment has been voided.,The payment has been voided. -We can't void the payment right now.,We can't void the payment right now. -Please correct the transaction ID and try again.,Please correct the transaction ID and try again. -The transaction details have been updated.,The transaction details have been updated. -We can't update the transaction details.,We can't update the transaction details. -Orders and Returns,Orders and Returns -You entered incorrect data. Please try again.,You entered incorrect data. Please try again. +"The coupon code has been accepted.","The coupon code has been accepted." +"Quote item id is not received.","Quote item id is not received." +"Quote item is not loaded.","Quote item is not loaded." +"New Order","New Order" +"You created the order.","You created the order." +"Order saving error: %1","Order saving error: %1" +"Cannot add new comment.","Cannot add new comment." +"The credit memo has been canceled.","The credit memo has been canceled." +"Credit memo has not been canceled.","Credit memo has not been canceled." +"New Memo for #%1","New Memo for #%1" +"New Memo","New Memo" +"The credit memo's total must be positive.","The credit memo's total must be positive." +"Cannot create online refund for Refund to Store Credit.","Cannot create online refund for Refund to Store Credit." +"You created the credit memo.","You created the credit memo." +"We can't save the credit memo right now.","We can't save the credit memo right now." +"We can't update the item's quantity right now.","We can't update the item's quantity right now." +"View Memo for #%1","View Memo for #%1" +"View Memo","View Memo" +"You voided the credit memo.","You voided the credit memo." +"We can't void the credit memo.","We can't void the credit memo." +"The order no longer exists.","The order no longer exists." +"We can't create credit memo for the order.","We can't create credit memo for the order." +"Edit Order","Edit Order" +"You sent the order email.","You sent the order email." +"We can't send the email order right now.","We can't send the email order right now." +"You have not put the order on hold.","You have not put the order on hold." +"You put the order on hold.","You put the order on hold." +"You canceled the invoice.","You canceled the invoice." +"Invoice canceling error","Invoice canceling error" +"The invoice has been captured.","The invoice has been captured." +"The order does not allow an invoice to be created.","The order does not allow an invoice to be created." +"You can't create an invoice without products.","You can't create an invoice without products." +"New Invoice","New Invoice" +"We can't save the invoice right now.","We can't save the invoice right now." +"You created the invoice and shipment.","You created the invoice and shipment." +"The invoice has been created.","The invoice has been created." +"We can't send the invoice email right now.","We can't send the invoice email right now." +"We can't send the shipment right now.","We can't send the shipment right now." +"Cannot update item quantity.","Cannot update item quantity." +"The invoice has been voided.","The invoice has been voided." +"Invoice voiding error","Invoice voiding error" +"%1 order(s) cannot be canceled.","%1 order(s) cannot be canceled." +"You cannot cancel the order(s).","You cannot cancel the order(s)." +"We canceled %1 order(s).","We canceled %1 order(s)." +"%1 order(s) were not put on hold.","%1 order(s) were not put on hold." +"No order(s) were put on hold.","No order(s) were put on hold." +"You have put %1 order(s) on hold.","You have put %1 order(s) on hold." +"%1 order(s) were not released from on hold status.","%1 order(s) were not released from on hold status." +"No order(s) were released from on hold status.","No order(s) were released from on hold status." +"%1 order(s) have been released from on hold status.","%1 order(s) have been released from on hold status." +"There are no printable documents related to selected orders.","There are no printable documents related to selected orders." +"The payment has been accepted.","The payment has been accepted." +"The payment has been denied.","The payment has been denied." +"Transaction has been approved.","Transaction has been approved." +"Transaction has been voided/declined.","Transaction has been voided/declined." +"There is no update for the transaction.","There is no update for the transaction." +"We can't update the payment right now.","We can't update the payment right now." +"You assigned the order status.","You assigned the order status." +"Something went wrong while assigning the order status.","Something went wrong while assigning the order status." +"We can't find this order status.","We can't find this order status." +"Create New Order Status","Create New Order Status" +"We found another order status with the same order status code.","We found another order status with the same order status code." +"You saved the order status.","You saved the order status." +"We can't add the order status right now.","We can't add the order status right now." +"You have unassigned the order status.","You have unassigned the order status." +"Something went wrong while unassigning the order.","Something went wrong while unassigning the order." +"Can't unhold order.","Can't unhold order." +"You released the order from holding status.","You released the order from holding status." +"The order was not on hold.","The order was not on hold." +"Exception occurred during order load","Exception occurred during order load" +"Something went wrong while saving the gift message.","Something went wrong while saving the gift message." +"You saved the gift card message.","You saved the gift card message." +"The payment has been voided.","The payment has been voided." +"We can't void the payment right now.","We can't void the payment right now." +"Please correct the transaction ID and try again.","Please correct the transaction ID and try again." +"The transaction details have been updated.","The transaction details have been updated." +"We can't update the transaction details.","We can't update the transaction details." +"Orders and Returns","Orders and Returns" +"You entered incorrect data. Please try again.","You entered incorrect data. Please try again." Home,Home -Go to Home Page,Go to Home Page -We can't find this wish list.,We can't find this wish list. +"Go to Home Page","Go to Home Page" +"We can't find this wish list.","We can't find this wish list." "We could not add a product to cart by the ID ""%1"".","We could not add a product to cart by the ID ""%1""." -There is an error in one of the option rows.,There is an error in one of the option rows. +"There is an error in one of the option rows.","There is an error in one of the option rows." "Shipping Address: ","Shipping Address: " "Billing Address: ","Billing Address: " -Please specify order items.,Please specify order items. -Please specify a shipping method.,Please specify a shipping method. -Please specify a payment method.,Please specify a payment method. -This payment method is not available.,This payment method is not available. -Validation is failed.,Validation is failed. -You did not email your customer. Please check your email settings.,You did not email your customer. Please check your email settings. --- Please Select --,-- Please Select -- +"Please specify order items.","Please specify order items." +"Please specify a shipping method.","Please specify a shipping method." +"Please specify a payment method.","Please specify a payment method." +"This payment method is not available.","This payment method is not available." +"Validation is failed.","Validation is failed." +"You did not email your customer. Please check your email settings.","You did not email your customer. Please check your email settings." +"-- Please Select --","-- Please Select --" "Path ""%1"" is not part of allowed directory ""%2""","Path ""%1"" is not part of allowed directory ""%2""" -Identifying Fields required,Identifying Fields required -Id required,Id required +"Identifying Fields required","Identifying Fields required" +"Id required","Id required" """Invoice Document Validation Error(s):\n"" .","""Invoice Document Validation Error(s):\n"" ." "Could not save an invoice, see error log for details","Could not save an invoice, see error log for details" -A hold action is not available.,A hold action is not available. -You cannot remove the hold.,You cannot remove the hold. -We cannot cancel this order.,We cannot cancel this order. +"A hold action is not available.","A hold action is not available." +"You cannot remove the hold.","You cannot remove the hold." +"We cannot cancel this order.","We cannot cancel this order." Guest,Guest -Please enter the first name.,Please enter the first name. -Please enter the last name.,Please enter the last name. -Please enter the street.,Please enter the street. -Please enter the city.,Please enter the city. -Please enter the phone number.,Please enter the phone number. -Please enter the company.,Please enter the company. -Please enter the fax number.,Please enter the fax number. -Please enter the zip/postal code.,Please enter the zip/postal code. -Please enter the country.,Please enter the country. -Please enter the state/province.,Please enter the state/province. -Requested entity doesn't exist,Requested entity doesn't exist -Could not delete order address,Could not delete order address -Could not save order address,Could not save order address +"Please enter the first name.","Please enter the first name." +"Please enter the last name.","Please enter the last name." +"Please enter the street.","Please enter the street." +"Please enter the city.","Please enter the city." +"Please enter the phone number.","Please enter the phone number." +"Please enter the company.","Please enter the company." +"Please enter the fax number.","Please enter the fax number." +"Please enter the zip/postal code.","Please enter the zip/postal code." +"Please enter the country.","Please enter the country." +"Please enter the state/province.","Please enter the state/province." +"Requested entity doesn't exist","Requested entity doesn't exist" +"Could not delete order address","Could not delete order address" +"Could not save order address","Could not save order address" Pending,Pending Refunded,Refunded Canceled,Canceled -Unknown State,Unknown State +"Unknown State","Unknown State" "We found an invalid quantity to refund item ""%1"".","We found an invalid quantity to refund item ""%1""." -The creditmemo contains product item that is not part of the original order.,The creditmemo contains product item that is not part of the original order. -The quantity to refund must not be greater than the unrefunded quantity.,The quantity to refund must not be greater than the unrefunded quantity. -Maximum shipping amount allowed to refund is: %1,Maximum shipping amount allowed to refund is: %1 -Order Id is required for creditmemo document,Order Id is required for creditmemo document +"The creditmemo contains product item that is not part of the original order.","The creditmemo contains product item that is not part of the original order." +"The quantity to refund must not be greater than the unrefunded quantity.","The quantity to refund must not be greater than the unrefunded quantity." +"Maximum shipping amount allowed to refund is: %1","Maximum shipping amount allowed to refund is: %1" +"Order Id is required for creditmemo document","Order Id is required for creditmemo document" "The creditmemo contains product SKU ""%1"" that is not part of the original order.","The creditmemo contains product SKU ""%1"" that is not part of the original order." "The quantity to creditmemo must not be greater than the unrefunded quantity for product SKU ""%1"".","The quantity to creditmemo must not be greater than the unrefunded quantity for product SKU ""%1""." -You can't create a creditmemo without products.,You can't create a creditmemo without products. -The most money available to refund is %1.,The most money available to refund is %1. -Could not delete credit memo,Could not delete credit memo -Could not save credit memo,Could not save credit memo -This order already has associated customer account,This order already has associated customer account +"You can't create a creditmemo without products.","You can't create a creditmemo without products." +"The most money available to refund is %1.","The most money available to refund is %1." +"Could not delete credit memo","Could not delete credit memo" +"Could not save credit memo","Could not save credit memo" +"This order already has associated customer account","This order already has associated customer account" Paid,Paid -We cannot register an existing invoice,We cannot register an existing invoice -We can't create creditmemo for the invoice.,We can't create creditmemo for the invoice. -Order Id is required for invoice document,Order Id is required for invoice document +"We cannot register an existing invoice","We cannot register an existing invoice" +"We can't create creditmemo for the invoice.","We can't create creditmemo for the invoice." +"Order Id is required for invoice document","Order Id is required for invoice document" "The quantity to invoice must not be greater than the uninvoiced quantity for product SKU ""%1"".","The quantity to invoice must not be greater than the uninvoiced quantity for product SKU ""%1""." -The invoice contains one or more items that are not part of the original order.,The invoice contains one or more items that are not part of the original order. -ID required,ID required -Unknown Status,Unknown Status +"The invoice contains one or more items that are not part of the original order.","The invoice contains one or more items that are not part of the original order." +"ID required","ID required" +"Unknown Status","Unknown Status" Ordered,Ordered Shipped,Shipped Invoiced,Invoiced @@ -346,462 +346,462 @@ Backordered,Backordered Returned,Returned Partial,Partial Mixed,Mixed -Registered a Void notification.,Registered a Void notification. +"Registered a Void notification.","Registered a Void notification." "If the invoice was created offline, try creating an offline credit memo.","If the invoice was created offline, try creating an offline credit memo." -We refunded %1 online.,We refunded %1 online. -We refunded %1 offline.,We refunded %1 offline. +"We refunded %1 online.","We refunded %1 online." +"We refunded %1 offline.","We refunded %1 offline." "IPN ""Refunded"". Refund issued by merchant. Registered notification about refunded amount of %1. Transaction ID: ""%2"". Credit Memo has not been created. Please create offline Credit Memo.","IPN ""Refunded"". Refund issued by merchant. Registered notification about refunded amount of %1. Transaction ID: ""%2"". Credit Memo has not been created. Please create offline Credit Memo." -The credit memo has been created automatically.,The credit memo has been created automatically. -Registered notification about refunded amount of %1.,Registered notification about refunded amount of %1. -Canceled order online,Canceled order online -Canceled order offline,Canceled order offline -Approved the payment online.,Approved the payment online. -There is no need to approve this payment.,There is no need to approve this payment. -Denied the payment online,Denied the payment online -Registered update about approved payment.,Registered update about approved payment. -Registered update about denied payment.,Registered update about denied payment. -There is no update for the payment.,There is no update for the payment. -Voided authorization.,Voided authorization. -Amount: %1.,Amount: %1. +"The credit memo has been created automatically.","The credit memo has been created automatically." +"Registered notification about refunded amount of %1.","Registered notification about refunded amount of %1." +"Canceled order online","Canceled order online" +"Canceled order offline","Canceled order offline" +"Approved the payment online.","Approved the payment online." +"There is no need to approve this payment.","There is no need to approve this payment." +"Denied the payment online","Denied the payment online" +"Registered update about approved payment.","Registered update about approved payment." +"Registered update about denied payment.","Registered update about denied payment." +"There is no update for the payment.","There is no update for the payment." +"Voided authorization.","Voided authorization." +"Amount: %1.","Amount: %1." "Transaction ID: ""%1""","Transaction ID: ""%1""" -The payment method you requested is not available.,The payment method you requested is not available. -The payment disallows storing objects.,The payment disallows storing objects. +"The payment method you requested is not available.","The payment method you requested is not available." +"The payment disallows storing objects.","The payment disallows storing objects." "The transaction ""%1"" cannot be captured yet.","The transaction ""%1"" cannot be captured yet." -The order amount of %1 is pending approval on the payment gateway.,The order amount of %1 is pending approval on the payment gateway. -Ordered amount of %1,Ordered amount of %1 -An amount of %1 will be captured after being approved at the payment gateway.,An amount of %1 will be captured after being approved at the payment gateway. -Registered notification about captured amount of %1.,Registered notification about captured amount of %1. -Order is suspended as its capture amount %1 is suspected to be fraudulent.,Order is suspended as its capture amount %1 is suspected to be fraudulent. -The parent transaction ID must have a transaction ID.,The parent transaction ID must have a transaction ID. -Payment transactions disallow storing objects.,Payment transactions disallow storing objects. +"The order amount of %1 is pending approval on the payment gateway.","The order amount of %1 is pending approval on the payment gateway." +"Ordered amount of %1","Ordered amount of %1" +"An amount of %1 will be captured after being approved at the payment gateway.","An amount of %1 will be captured after being approved at the payment gateway." +"Registered notification about captured amount of %1.","Registered notification about captured amount of %1." +"Order is suspended as its capture amount %1 is suspected to be fraudulent.","Order is suspended as its capture amount %1 is suspected to be fraudulent." +"The parent transaction ID must have a transaction ID.","The parent transaction ID must have a transaction ID." +"Payment transactions disallow storing objects.","Payment transactions disallow storing objects." "The transaction ""%1"" (%2) is already closed.","The transaction ""%1"" (%2) is already closed." -Set order for existing transactions not allowed,Set order for existing transactions not allowed +"Set order for existing transactions not allowed","Set order for existing transactions not allowed" "At minimum, you need to set a payment ID.","At minimum, you need to set a payment ID." Order,Order Authorization,Authorization "We found an unsupported transaction type ""%1"".","We found an unsupported transaction type ""%1""." -Please set a proper payment and order id.,Please set a proper payment and order id. -Please enter a Transaction ID.,Please enter a Transaction ID. -You can't do this without a transaction object.,You can't do this without a transaction object. +"Please set a proper payment and order id.","Please set a proper payment and order id." +"Please enter a Transaction ID.","Please enter a Transaction ID." +"You can't do this without a transaction object.","You can't do this without a transaction object." "Order # ","Order # " "Order Date: ","Order Date: " -Sold to:,Sold to: -Ship to:,Ship to: -Payment Method:,Payment Method: -Shipping Method:,Shipping Method: -Total Shipping Charges,Total Shipping Charges +"Sold to:","Sold to:" +"Ship to:","Ship to:" +"Payment Method:","Payment Method:" +"Shipping Method:","Shipping Method:" +"Total Shipping Charges","Total Shipping Charges" Title,Title Number,Number -We found an invalid renderer model.,We found an invalid renderer model. -Please define the PDF object before using.,Please define the PDF object before using. +"We found an invalid renderer model.","We found an invalid renderer model." +"Please define the PDF object before using.","Please define the PDF object before using." "We don't recognize the draw line data. Please define the ""lines"" array.","We don't recognize the draw line data. Please define the ""lines"" array." Products,Products -Total (ex),Total (ex) +"Total (ex)","Total (ex)" Qty,Qty Tax,Tax -Total (inc),Total (inc) +"Total (inc)","Total (inc)" "Credit Memo # ","Credit Memo # " "Invoice # ","Invoice # " -The order object is not specified.,The order object is not specified. -The source object is not specified.,The source object is not specified. -An item object is not specified.,An item object is not specified. -A PDF object is not specified.,A PDF object is not specified. -A PDF page object is not specified.,A PDF page object is not specified. -Excl. Tax,Excl. Tax -Incl. Tax,Incl. Tax +"The order object is not specified.","The order object is not specified." +"The source object is not specified.","The source object is not specified." +"An item object is not specified.","An item object is not specified." +"A PDF object is not specified.","A PDF object is not specified." +"A PDF page object is not specified.","A PDF page object is not specified." +"Excl. Tax","Excl. Tax" +"Incl. Tax","Incl. Tax" "Packing Slip # ","Packing Slip # " title,title -The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal.,The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal. -We cannot register an existing shipment,We cannot register an existing shipment -Parent shipment cannot be loaded for track object.,Parent shipment cannot be loaded for track object. -Order Id is required for shipment document,Order Id is required for shipment document -You can't create a shipment without products.,You can't create a shipment without products. +"The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal.","The PDF total model %1 must be or extend \Magento\Sales\Model\Order\Pdf\Total\DefaultTotal." +"We cannot register an existing shipment","We cannot register an existing shipment" +"Parent shipment cannot be loaded for track object.","Parent shipment cannot be loaded for track object." +"Order Id is required for shipment document","Order Id is required for shipment document" +"You can't create a shipment without products.","You can't create a shipment without products." "The shipment contains product SKU ""%1"" that is not part of the original order.","The shipment contains product SKU ""%1"" that is not part of the original order." "The quantity to ship must not be greater than the unshipped quantity for product SKU ""%1"".","The quantity to ship must not be greater than the unshipped quantity for product SKU ""%1""." -Please enter a tracking number.,Please enter a tracking number. -Could not delete shipment,Could not delete shipment -Could not save shipment,Could not save shipment -The last status can't be unassigned from its current state.,The last status can't be unassigned from its current state. +"Please enter a tracking number.","Please enter a tracking number." +"Could not delete shipment","Could not delete shipment" +"Could not save shipment","Could not save shipment" +"The last status can't be unassigned from its current state.","The last status can't be unassigned from its current state." "Status can't be unassigned, because it is used by existing order(s).","Status can't be unassigned, because it is used by existing order(s)." -The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal.,The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal. -An invoice cannot be created when an order has a status of %1,An invoice cannot be created when an order has a status of %1 -A creditmemo can not be created when an order has a status of %1,A creditmemo can not be created when an order has a status of %1 -The order does not allow a creditmemo to be created.,The order does not allow a creditmemo to be created. -A shipment cannot be created when an order has a status of %1,A shipment cannot be created when an order has a status of %1 -The order does not allow a shipment to be created.,The order does not allow a shipment to be created. +"The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal.","The total model should be extended from \Magento\Sales\Model\Order\Total\AbstractTotal." +"An invoice cannot be created when an order has a status of %1","An invoice cannot be created when an order has a status of %1" +"A creditmemo can not be created when an order has a status of %1","A creditmemo can not be created when an order has a status of %1" +"The order does not allow a creditmemo to be created.","The order does not allow a creditmemo to be created." +"A shipment cannot be created when an order has a status of %1","A shipment cannot be created when an order has a status of %1" +"The order does not allow a shipment to be created.","The order does not allow a shipment to be created." """Creditmemo Document Validation Error(s):\n"" .","""Creditmemo Document Validation Error(s):\n"" ." "Could not save a Creditmemo, see error log for details","Could not save a Creditmemo, see error log for details" -We cannot determine the field name.,We cannot determine the field name. +"We cannot determine the field name.","We cannot determine the field name." City,City Company,Company Country,Country Email,Email -First Name,First Name -Last Name,Last Name +"First Name","First Name" +"Last Name","Last Name" State/Province,State/Province -Street Address,Street Address -Phone Number,Phone Number -Zip/Postal Code,Zip/Postal Code -We can't save the address:\n%1,We can't save the address:\n%1 -Cannot save comment:\n%1,Cannot save comment:\n%1 -We don't have enough information to save the parent transaction ID.,We don't have enough information to save the parent transaction ID. -We cannot create an empty shipment.,We cannot create an empty shipment. -Cannot save track:\n%1,Cannot save track:\n%1 -Cannot unassign status from state,Cannot unassign status from state -New Orders,New Orders -Order #%1 created at %2,Order #%1 created at %2 -Details for %1 #%2,Details for %1 #%2 -Notified Date: %1,Notified Date: %1 -Comment: %1<br/>,Comment: %1<br/> -Current Status: %1<br/>,Current Status: %1<br/> -Total: %1<br/>,Total: %1<br/> -Order # %1 Notification(s),Order # %1 Notification(s) -You can not cancel Credit Memo,You can not cancel Credit Memo -Could not cancel creditmemo,Could not cancel creditmemo -We cannot register an existing credit memo.,We cannot register an existing credit memo. +"Street Address","Street Address" +"Phone Number","Phone Number" +"Zip/Postal Code","Zip/Postal Code" +"We can't save the address:\n%1","We can't save the address:\n%1" +"Cannot save comment:\n%1","Cannot save comment:\n%1" +"We don't have enough information to save the parent transaction ID.","We don't have enough information to save the parent transaction ID." +"We cannot create an empty shipment.","We cannot create an empty shipment." +"Cannot save track:\n%1","Cannot save track:\n%1" +"Cannot unassign status from state","Cannot unassign status from state" +"New Orders","New Orders" +"Order #%1 created at %2","Order #%1 created at %2" +"Details for %1 #%2","Details for %1 #%2" +"Notified Date: %1","Notified Date: %1" +"Comment: %1<br/>","Comment: %1<br/>" +"Current Status: %1<br/>","Current Status: %1<br/>" +"Total: %1<br/>","Total: %1<br/>" +"Order # %1 Notification(s)","Order # %1 Notification(s)" +"You can not cancel Credit Memo","You can not cancel Credit Memo" +"Could not cancel creditmemo","Could not cancel creditmemo" +"We cannot register an existing credit memo.","We cannot register an existing credit memo." "We found an invalid quantity to invoice item ""%1"".","We found an invalid quantity to invoice item ""%1""." "The Order State ""%1"" must not be set manually.","The Order State ""%1"" must not be set manually." """Shipment Document Validation Error(s):\n"" .","""Shipment Document Validation Error(s):\n"" ." "Could not save a shipment, see error log for details","Could not save a shipment, see error log for details" -VAT Request Identifier,VAT Request Identifier -VAT Request Date,VAT Request Date -Pending Payment,Pending Payment +"VAT Request Identifier","VAT Request Identifier" +"VAT Request Date","VAT Request Date" +"Pending Payment","Pending Payment" Processing,Processing -On Hold,On Hold +"On Hold","On Hold" Complete,Complete Closed,Closed -Suspected Fraud,Suspected Fraud -Payment Review,Payment Review +"Suspected Fraud","Suspected Fraud" +"Payment Review","Payment Review" New,New -test message,test message -Email has not been sent,Email has not been sent -Authorized amount of %1.,Authorized amount of %1. -We will authorize %1 after the payment is approved at the payment gateway.,We will authorize %1 after the payment is approved at the payment gateway. -Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent.,Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent. -Captured amount of %1 online.,Captured amount of %1 online. -Authorized amount of %1,Authorized amount of %1 +"test message","test message" +"Email has not been sent","Email has not been sent" +"Authorized amount of %1.","Authorized amount of %1." +"We will authorize %1 after the payment is approved at the payment gateway.","We will authorize %1 after the payment is approved at the payment gateway." +"Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent.","Authorized amount of %1. Order is suspended as its authorizing amount %1 is suspected to be fraudulent." +"Captured amount of %1 online.","Captured amount of %1 online." +"Authorized amount of %1","Authorized amount of %1" " Transaction ID: ""%1"""," Transaction ID: ""%1""" View,View -Group was removed,Group was removed +"Group was removed","Group was removed" "Changing address information will not recalculate shipping, tax or other order amount.","Changing address information will not recalculate shipping, tax or other order amount." -Comment Text,Comment Text -Notify Customer by Email,Notify Customer by Email -Visible on Storefront,Visible on Storefront +"Comment Text","Comment Text" +"Notify Customer by Email","Notify Customer by Email" +"Visible on Storefront","Visible on Storefront" Customer,Customer Notified,Notified -Not Notified,Not Notified -No Payment Methods,No Payment Methods -Order Comments,Order Comments -Apply Coupon Code,Apply Coupon Code +"Not Notified","Not Notified" +"No Payment Methods","No Payment Methods" +"Order Comments","Order Comments" +"Apply Coupon Code","Apply Coupon Code" Apply,Apply -Remove Coupon Code,Remove Coupon Code +"Remove Coupon Code","Remove Coupon Code" Remove,Remove -Address Information,Address Information -Payment & Shipping Information,Payment & Shipping Information -Order Total,Order Total -Order Currency:,Order Currency: -Same As Billing Address,Same As Billing Address -Select from existing customer addresses:,Select from existing customer addresses: -Add New Address,Add New Address -Save in address book,Save in address book -You don't need to select a shipping address.,You don't need to select a shipping address. -Gift Message for the Entire Order,Gift Message for the Entire Order -Leave this box blank if you don't want to leave a gift message for the entire order.,Leave this box blank if you don't want to leave a gift message for the entire order. -Row Subtotal,Row Subtotal +"Address Information","Address Information" +"Payment & Shipping Information","Payment & Shipping Information" +"Order Total","Order Total" +"Order Currency:","Order Currency:" +"Same As Billing Address","Same As Billing Address" +"Select from existing customer addresses:","Select from existing customer addresses:" +"Add New Address","Add New Address" +"Save in address book","Save in address book" +"You don't need to select a shipping address.","You don't need to select a shipping address." +"Gift Message for the Entire Order","Gift Message for the Entire Order" +"Leave this box blank if you don't want to leave a gift message for the entire order.","Leave this box blank if you don't want to leave a gift message for the entire order." +"Row Subtotal","Row Subtotal" Action,Action -No ordered items,No ordered items -Update Items and Quantities,Update Items and Quantities -Total %1 product(s),Total %1 product(s) +"No ordered items","No ordered items" +"Update Items and Quantities","Update Items and Quantities" +"Total %1 product(s)","Total %1 product(s)" Subtotal:,Subtotal: -Tier Pricing,Tier Pricing -Custom Price,Custom Price -Please select,Please select -Move to Shopping Cart,Move to Shopping Cart -Move to Wish List,Move to Wish List -Subscribe to Newsletter,Subscribe to Newsletter -Click to change shipping method,Click to change shipping method +"Tier Pricing","Tier Pricing" +"Custom Price","Custom Price" +"Please select","Please select" +"Move to Shopping Cart","Move to Shopping Cart" +"Move to Wish List","Move to Wish List" +"Subscribe to Newsletter","Subscribe to Newsletter" +"Click to change shipping method","Click to change shipping method" "Sorry, no quotes are available for this order.","Sorry, no quotes are available for this order." -Get shipping methods and rates,Get shipping methods and rates -You don't need to select a shipping method.,You don't need to select a shipping method. -Customer's Activities,Customer's Activities +"Get shipping methods and rates","Get shipping methods and rates" +"You don't need to select a shipping method.","You don't need to select a shipping method." +"Customer's Activities","Customer's Activities" Refresh,Refresh Item,Item -Add To Order,Add To Order -Configure and Add to Order,Configure and Add to Order -No items,No items -Append Comments,Append Comments -Email Order Confirmation,Email Order Confirmation -Grand Total Excl. Tax,Grand Total Excl. Tax -Grand Total Incl. Tax,Grand Total Incl. Tax -Subtotal (Excl. Tax),Subtotal (Excl. Tax) -Subtotal (Incl. Tax),Subtotal (Incl. Tax) -Payment & Shipping Method,Payment & Shipping Method -Payment Information,Payment Information -The order was placed using %1.,The order was placed using %1. -Shipping Information,Shipping Information -Items to Refund,Items to Refund -Return to Stock,Return to Stock -Qty to Refund,Qty to Refund -Tax Amount,Tax Amount -Discount Amount,Discount Amount -Row Total,Row Total -No Items To Refund,No Items To Refund -Credit Memo Comments,Credit Memo Comments -Refund Totals,Refund Totals -Email Copy of Credit Memo,Email Copy of Credit Memo -Please enter a positive number in this field.,Please enter a positive number in this field. -Items Refunded,Items Refunded -No Items,No Items -Memo Total,Memo Total -Credit Memo History,Credit Memo History -Credit Memo Totals,Credit Memo Totals -Customer Name: %1,Customer Name: %1 -Purchased From: %1,Purchased From: %1 -Gift Message,Gift Message +"Add To Order","Add To Order" +"Configure and Add to Order","Configure and Add to Order" +"No items","No items" +"Append Comments","Append Comments" +"Email Order Confirmation","Email Order Confirmation" +"Grand Total Excl. Tax","Grand Total Excl. Tax" +"Grand Total Incl. Tax","Grand Total Incl. Tax" +"Subtotal (Excl. Tax)","Subtotal (Excl. Tax)" +"Subtotal (Incl. Tax)","Subtotal (Incl. Tax)" +"Payment & Shipping Method","Payment & Shipping Method" +"Payment Information","Payment Information" +"The order was placed using %1.","The order was placed using %1." +"Shipping Information","Shipping Information" +"Items to Refund","Items to Refund" +"Return to Stock","Return to Stock" +"Qty to Refund","Qty to Refund" +"Tax Amount","Tax Amount" +"Discount Amount","Discount Amount" +"Row Total","Row Total" +"No Items To Refund","No Items To Refund" +"Credit Memo Comments","Credit Memo Comments" +"Refund Totals","Refund Totals" +"Email Copy of Credit Memo","Email Copy of Credit Memo" +"Please enter a positive number in this field.","Please enter a positive number in this field." +"Items Refunded","Items Refunded" +"No Items","No Items" +"Memo Total","Memo Total" +"Credit Memo History","Credit Memo History" +"Credit Memo Totals","Credit Memo Totals" +"Customer Name: %1","Customer Name: %1" +"Purchased From: %1","Purchased From: %1" +"Gift Message","Gift Message" From:,From: To:,To: Message:,Message: -Shipping & Handling,Shipping & Handling -Gift Options,Gift Options -Create Shipment,Create Shipment -Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice.,Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice. +"Shipping & Handling","Shipping & Handling" +"Gift Options","Gift Options" +"Create Shipment","Create Shipment" +"Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice.","Invoice and shipment types do not match for some items on this order. You can create a shipment only after creating the invoice." %1,%1 -Qty to Invoice,Qty to Invoice -Invoice History,Invoice History -Invoice Comments,Invoice Comments -Invoice Totals,Invoice Totals +"Qty to Invoice","Qty to Invoice" +"Invoice History","Invoice History" +"Invoice Comments","Invoice Comments" +"Invoice Totals","Invoice Totals" Amount,Amount -Capture Online,Capture Online -Capture Offline,Capture Offline -Not Capture,Not Capture -The invoice will be created offline without the payment gateway.,The invoice will be created offline without the payment gateway. -Email Copy of Invoice,Email Copy of Invoice -Items Invoiced,Items Invoiced -Total Tax,Total Tax -From Name,From Name -To Name,To Name +"Capture Online","Capture Online" +"Capture Offline","Capture Offline" +"Not Capture","Not Capture" +"The invoice will be created offline without the payment gateway.","The invoice will be created offline without the payment gateway." +"Email Copy of Invoice","Email Copy of Invoice" +"Items Invoiced","Items Invoiced" +"Total Tax","Total Tax" +"From Name","From Name" +"To Name","To Name" Status,Status Comment,Comment -Notification Not Applicable,Notification Not Applicable -Order & Account Information,Order & Account Information -The order confirmation email was sent,The order confirmation email was sent -The order confirmation email is not sent,The order confirmation email is not sent -Order Date,Order Date -Order Date (%1),Order Date (%1) -Purchased From,Purchased From -Link to the New Order,Link to the New Order -Link to the Previous Order,Link to the Previous Order -Placed from IP,Placed from IP -%1 / %2 rate:,%1 / %2 rate: -Customer Name,Customer Name -Customer Group,Customer Group -Notes for this Order,Notes for this Order -Comment added,Comment added -Transaction Data,Transaction Data -Transaction ID,Transaction ID -Parent Transaction ID,Parent Transaction ID -Order ID,Order ID -Transaction Type,Transaction Type -Is Closed,Is Closed -Created At,Created At -Child Transactions,Child Transactions -Transaction Details,Transaction Details +"Notification Not Applicable","Notification Not Applicable" +"Order & Account Information","Order & Account Information" +"The order confirmation email was sent","The order confirmation email was sent" +"The order confirmation email is not sent","The order confirmation email is not sent" +"Order Date","Order Date" +"Order Date (%1)","Order Date (%1)" +"Purchased From","Purchased From" +"Link to the New Order","Link to the New Order" +"Link to the Previous Order","Link to the Previous Order" +"Placed from IP","Placed from IP" +"%1 / %2 rate:","%1 / %2 rate:" +"Customer Name","Customer Name" +"Customer Group","Customer Group" +"Notes for this Order","Notes for this Order" +"Comment added","Comment added" +"Transaction Data","Transaction Data" +"Transaction ID","Transaction ID" +"Parent Transaction ID","Parent Transaction ID" +"Order ID","Order ID" +"Transaction Type","Transaction Type" +"Is Closed","Is Closed" +"Created At","Created At" +"Child Transactions","Child Transactions" +"Transaction Details","Transaction Details" Items,Items -Gift Message for this Order,Gift Message for this Order -Shipped By,Shipped By -Tracking Number,Tracking Number -Billing Last Name,Billing Last Name -Find Order By,Find Order By -ZIP Code,ZIP Code -Billing ZIP Code,Billing ZIP Code +"Gift Message for this Order","Gift Message for this Order" +"Shipped By","Shipped By" +"Tracking Number","Tracking Number" +"Billing Last Name","Billing Last Name" +"Find Order By","Find Order By" +"ZIP Code","ZIP Code" +"Billing ZIP Code","Billing ZIP Code" Continue,Continue -Print All Refunds,Print All Refunds -Refund #,Refund # -Print Refund,Print Refund -Product Name,Product Name -Order #,Order # +"Print All Refunds","Print All Refunds" +"Refund #","Refund #" +"Print Refund","Print Refund" +"Product Name","Product Name" +"Order #","Order #" Date,Date -Ship To,Ship To +"Ship To","Ship To" Actions,Actions -View Order,View Order -You have placed no orders.,You have placed no orders. -No shipping information available,No shipping information available -Print Order,Print Order -Print All Invoices,Print All Invoices -Invoice #,Invoice # -Print Invoice,Print Invoice -Qty Invoiced,Qty Invoiced +"View Order","View Order" +"You have placed no orders.","You have placed no orders." +"No shipping information available","No shipping information available" +"Print Order","Print Order" +"Print All Invoices","Print All Invoices" +"Invoice #","Invoice #" +"Print Invoice","Print Invoice" +"Qty Invoiced","Qty Invoiced" Close,Close -About Your Order,About Your Order +"About Your Order","About Your Order" "<span class=""label"">Order Date:</span> %1","<span class=""label"">Order Date:</span> %1" -Refund #%1,Refund #%1 -Shipment #%1,Shipment #%1 -Qty Shipped,Qty Shipped -Recent Orders,Recent Orders -View All,View All -Gift Message for This Order,Gift Message for This Order -Recently Ordered,Recently Ordered -Add to Cart,Add to Cart +"Refund #%1","Refund #%1" +"Shipment #%1","Shipment #%1" +"Qty Shipped","Qty Shipped" +"Recent Orders","Recent Orders" +"View All","View All" +"Gift Message for This Order","Gift Message for This Order" +"Recently Ordered","Recently Ordered" +"Add to Cart","Add to Cart" Search,Search -Credit memo for your %store_name order,Credit memo for your %store_name order +"Credit memo for your %store_name order","Credit memo for your %store_name order" "%name,","%name," -Thank you for your order from %store_name.,Thank you for your order from %store_name. +"Thank you for your order from %store_name.","Thank you for your order from %store_name." "You can check the status of your order by <a href=""%account_url"">logging into your account</a>.","You can check the status of your order by <a href=""%account_url"">logging into your account</a>." "If you have questions about your order, you can email us at <a href=""mailto:%store_email"">%store_email</a>","If you have questions about your order, you can email us at <a href=""mailto:%store_email"">%store_email</a>" "or call us at <a href=""tel:%store_phone"">%store_phone</a>","or call us at <a href=""tel:%store_phone"">%store_phone</a>" "Our hours are <span class=""no-link"">%store_hours</span>.","Our hours are <span class=""no-link"">%store_hours</span>." -Your Credit Memo #%creditmemo_id for Order #%order_id,Your Credit Memo #%creditmemo_id for Order #%order_id -Billing Info,Billing Info -Shipping Info,Shipping Info -Update to your %store_name credit memo,Update to your %store_name credit memo -Your order #%increment_id has been updated with a status of <strong>%order_status</strong>.,Your order #%increment_id has been updated with a status of <strong>%order_status</strong>. -Invoice for your %store_name order,Invoice for your %store_name order -Your Invoice #%invoice_id for Order #%order_id,Your Invoice #%invoice_id for Order #%order_id -Update to your %store_name invoice,Update to your %store_name invoice -Your %store_name order confirmation,Your %store_name order confirmation +"Your Credit Memo #%creditmemo_id for Order #%order_id","Your Credit Memo #%creditmemo_id for Order #%order_id" +"Billing Info","Billing Info" +"Shipping Info","Shipping Info" +"Update to your %store_name credit memo","Update to your %store_name credit memo" +"Your order #%increment_id has been updated with a status of <strong>%order_status</strong>.","Your order #%increment_id has been updated with a status of <strong>%order_status</strong>." +"Invoice for your %store_name order","Invoice for your %store_name order" +"Your Invoice #%invoice_id for Order #%order_id","Your Invoice #%invoice_id for Order #%order_id" +"Update to your %store_name invoice","Update to your %store_name invoice" +"Your %store_name order confirmation","Your %store_name order confirmation" "%customer_name,","%customer_name," -Once your package ships we will send you a tracking number.,Once your package ships we will send you a tracking number. +"Once your package ships we will send you a tracking number.","Once your package ships we will send you a tracking number." "Your Order <span class=""no-link"">#%increment_id</span>","Your Order <span class=""no-link"">#%increment_id</span>" "Placed on <span class=""no-link"">%created_at</span>","Placed on <span class=""no-link"">%created_at</span>" -Once your package ships we will send an email with a link to track your order.,Once your package ships we will send an email with a link to track your order. -Update to your %store_name order,Update to your %store_name order -Your %store_name order has shipped,Your %store_name order has shipped -Your shipping confirmation is below. Thank you again for your business.,Your shipping confirmation is below. Thank you again for your business. -Your Shipment #%shipment_id for Order #%order_id,Your Shipment #%shipment_id for Order #%order_id -Update to your %store_name shipment,Update to your %store_name shipment +"Once your package ships we will send an email with a link to track your order.","Once your package ships we will send an email with a link to track your order." +"Update to your %store_name order","Update to your %store_name order" +"Your %store_name order has shipped","Your %store_name order has shipped" +"Your shipping confirmation is below. Thank you again for your business.","Your shipping confirmation is below. Thank you again for your business." +"Your Shipment #%shipment_id for Order #%order_id","Your Shipment #%shipment_id for Order #%order_id" +"Update to your %store_name shipment","Update to your %store_name shipment" "Gift Options for ","Gift Options for " -Add Products,Add Products -You have item changes,You have item changes +"Add Products","Add Products" +"You have item changes","You have item changes" Ok,Ok Operations,Operations Create,Create -Send Order Email,Send Order Email -Accept or Deny Payment,Accept or Deny Payment -Send Sales Emails,Send Sales Emails -Sales Section,Sales Section -Sales Emails Section,Sales Emails Section +"Send Order Email","Send Order Email" +"Accept or Deny Payment","Accept or Deny Payment" +"Send Sales Emails","Send Sales Emails" +"Sales Section","Sales Section" +"Sales Emails Section","Sales Emails Section" General,General -Hide Customer IP,Hide Customer IP +"Hide Customer IP","Hide Customer IP" "Choose whether a customer IP is shown in orders, invoices, shipments, and credit memos.","Choose whether a customer IP is shown in orders, invoices, shipments, and credit memos." -Checkout Totals Sort Order,Checkout Totals Sort Order -Allow Reorder,Allow Reorder -Invoice and Packing Slip Design,Invoice and Packing Slip Design -Logo for PDF Print-outs (200x50),Logo for PDF Print-outs (200x50) +"Checkout Totals Sort Order","Checkout Totals Sort Order" +"Allow Reorder","Allow Reorder" +"Invoice and Packing Slip Design","Invoice and Packing Slip Design" +"Logo for PDF Print-outs (200x50)","Logo for PDF Print-outs (200x50)" "Your default logo will be used in PDF and HTML documents.<br />(jpeg, tiff, png) If your pdf image is distorted, try to use larger file-size image.","Your default logo will be used in PDF and HTML documents.<br />(jpeg, tiff, png) If your pdf image is distorted, try to use larger file-size image." -Logo for HTML Print View,Logo for HTML Print View +"Logo for HTML Print View","Logo for HTML Print View" "Logo for HTML documents only. If empty, default will be used.<br />(jpeg, gif, png)","Logo for HTML documents only. If empty, default will be used.<br />(jpeg, gif, png)" Address,Address -Minimum Order Amount,Minimum Order Amount +"Minimum Order Amount","Minimum Order Amount" Enable,Enable -Minimum Amount,Minimum Amount -Subtotal after discount,Subtotal after discount -Include Tax to Amount,Include Tax to Amount -Description Message,Description Message -This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount.,This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount. -Error to Show in Shopping Cart,Error to Show in Shopping Cart -Validate Each Address Separately in Multi-address Checkout,Validate Each Address Separately in Multi-address Checkout -Multi-address Description Message,Multi-address Description Message -We'll use the default description above if you leave this empty.,We'll use the default description above if you leave this empty. -Multi-address Error to Show in Shopping Cart,Multi-address Error to Show in Shopping Cart -We'll use the default error above if you leave this empty.,We'll use the default error above if you leave this empty. +"Minimum Amount","Minimum Amount" +"Subtotal after discount","Subtotal after discount" +"Include Tax to Amount","Include Tax to Amount" +"Description Message","Description Message" +"This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount.","This message will be shown in the shopping cart when the subtotal (after discount) is lower than the minimum allowed amount." +"Error to Show in Shopping Cart","Error to Show in Shopping Cart" +"Validate Each Address Separately in Multi-address Checkout","Validate Each Address Separately in Multi-address Checkout" +"Multi-address Description Message","Multi-address Description Message" +"We'll use the default description above if you leave this empty.","We'll use the default description above if you leave this empty." +"Multi-address Error to Show in Shopping Cart","Multi-address Error to Show in Shopping Cart" +"We'll use the default error above if you leave this empty.","We'll use the default error above if you leave this empty." Dashboard,Dashboard -Use Aggregated Data,Use Aggregated Data -Orders Cron Settings,Orders Cron Settings -Pending Payment Order Lifetime (minutes),Pending Payment Order Lifetime (minutes) -Sales Emails,Sales Emails -Asynchronous sending,Asynchronous sending +"Use Aggregated Data","Use Aggregated Data" +"Orders Cron Settings","Orders Cron Settings" +"Pending Payment Order Lifetime (minutes)","Pending Payment Order Lifetime (minutes)" +"Sales Emails","Sales Emails" +"Asynchronous sending","Asynchronous sending" Enabled,Enabled -New Order Confirmation Email Sender,New Order Confirmation Email Sender -New Order Confirmation Template,New Order Confirmation Template +"New Order Confirmation Email Sender","New Order Confirmation Email Sender" +"New Order Confirmation Template","New Order Confirmation Template" "Email template chosen based on theme fallback when ""Default"" option is selected.","Email template chosen based on theme fallback when ""Default"" option is selected." -New Order Confirmation Template for Guest,New Order Confirmation Template for Guest -Send Order Email Copy To,Send Order Email Copy To +"New Order Confirmation Template for Guest","New Order Confirmation Template for Guest" +"Send Order Email Copy To","Send Order Email Copy To" Comma-separated,Comma-separated -Send Order Email Copy Method,Send Order Email Copy Method -Order Comment Email Sender,Order Comment Email Sender -Order Comment Email Template,Order Comment Email Template -Order Comment Email Template for Guest,Order Comment Email Template for Guest -Send Order Comment Email Copy To,Send Order Comment Email Copy To -Send Order Comments Email Copy Method,Send Order Comments Email Copy Method -Invoice Email Sender,Invoice Email Sender -Invoice Email Template,Invoice Email Template -Invoice Email Template for Guest,Invoice Email Template for Guest -Send Invoice Email Copy To,Send Invoice Email Copy To -Send Invoice Email Copy Method,Send Invoice Email Copy Method -Invoice Comment Email Sender,Invoice Comment Email Sender -Invoice Comment Email Template,Invoice Comment Email Template -Invoice Comment Email Template for Guest,Invoice Comment Email Template for Guest -Send Invoice Comment Email Copy To,Send Invoice Comment Email Copy To -Send Invoice Comments Email Copy Method,Send Invoice Comments Email Copy Method +"Send Order Email Copy Method","Send Order Email Copy Method" +"Order Comment Email Sender","Order Comment Email Sender" +"Order Comment Email Template","Order Comment Email Template" +"Order Comment Email Template for Guest","Order Comment Email Template for Guest" +"Send Order Comment Email Copy To","Send Order Comment Email Copy To" +"Send Order Comments Email Copy Method","Send Order Comments Email Copy Method" +"Invoice Email Sender","Invoice Email Sender" +"Invoice Email Template","Invoice Email Template" +"Invoice Email Template for Guest","Invoice Email Template for Guest" +"Send Invoice Email Copy To","Send Invoice Email Copy To" +"Send Invoice Email Copy Method","Send Invoice Email Copy Method" +"Invoice Comment Email Sender","Invoice Comment Email Sender" +"Invoice Comment Email Template","Invoice Comment Email Template" +"Invoice Comment Email Template for Guest","Invoice Comment Email Template for Guest" +"Send Invoice Comment Email Copy To","Send Invoice Comment Email Copy To" +"Send Invoice Comments Email Copy Method","Send Invoice Comments Email Copy Method" Shipment,Shipment -Shipment Email Sender,Shipment Email Sender -Shipment Email Template,Shipment Email Template -Shipment Email Template for Guest,Shipment Email Template for Guest -Send Shipment Email Copy To,Send Shipment Email Copy To -Send Shipment Email Copy Method,Send Shipment Email Copy Method -Shipment Comments,Shipment Comments -Shipment Comment Email Sender,Shipment Comment Email Sender -Shipment Comment Email Template,Shipment Comment Email Template -Shipment Comment Email Template for Guest,Shipment Comment Email Template for Guest -Send Shipment Comment Email Copy To,Send Shipment Comment Email Copy To -Send Shipment Comments Email Copy Method,Send Shipment Comments Email Copy Method -Credit Memo Email Sender,Credit Memo Email Sender -Credit Memo Email Template,Credit Memo Email Template -Credit Memo Email Template for Guest,Credit Memo Email Template for Guest -Send Credit Memo Email Copy To,Send Credit Memo Email Copy To -Send Credit Memo Email Copy Method,Send Credit Memo Email Copy Method -Credit Memo Comment Email Sender,Credit Memo Comment Email Sender -Credit Memo Comment Email Template,Credit Memo Comment Email Template -Credit Memo Comment Email Template for Guest,Credit Memo Comment Email Template for Guest -Send Credit Memo Comment Email Copy To,Send Credit Memo Comment Email Copy To -Send Credit Memo Comments Email Copy Method,Send Credit Memo Comments Email Copy Method -PDF Print-outs,PDF Print-outs -Display Order ID in Header,Display Order ID in Header -Customer Order Status Notification,Customer Order Status Notification -Asynchronous indexing,Asynchronous indexing -Orders and Returns Search Form,Orders and Returns Search Form -Anchor Custom Title,Anchor Custom Title +"Shipment Email Sender","Shipment Email Sender" +"Shipment Email Template","Shipment Email Template" +"Shipment Email Template for Guest","Shipment Email Template for Guest" +"Send Shipment Email Copy To","Send Shipment Email Copy To" +"Send Shipment Email Copy Method","Send Shipment Email Copy Method" +"Shipment Comments","Shipment Comments" +"Shipment Comment Email Sender","Shipment Comment Email Sender" +"Shipment Comment Email Template","Shipment Comment Email Template" +"Shipment Comment Email Template for Guest","Shipment Comment Email Template for Guest" +"Send Shipment Comment Email Copy To","Send Shipment Comment Email Copy To" +"Send Shipment Comments Email Copy Method","Send Shipment Comments Email Copy Method" +"Credit Memo Email Sender","Credit Memo Email Sender" +"Credit Memo Email Template","Credit Memo Email Template" +"Credit Memo Email Template for Guest","Credit Memo Email Template for Guest" +"Send Credit Memo Email Copy To","Send Credit Memo Email Copy To" +"Send Credit Memo Email Copy Method","Send Credit Memo Email Copy Method" +"Credit Memo Comment Email Sender","Credit Memo Comment Email Sender" +"Credit Memo Comment Email Template","Credit Memo Comment Email Template" +"Credit Memo Comment Email Template for Guest","Credit Memo Comment Email Template for Guest" +"Send Credit Memo Comment Email Copy To","Send Credit Memo Comment Email Copy To" +"Send Credit Memo Comments Email Copy Method","Send Credit Memo Comments Email Copy Method" +"PDF Print-outs","PDF Print-outs" +"Display Order ID in Header","Display Order ID in Header" +"Customer Order Status Notification","Customer Order Status Notification" +"Asynchronous indexing","Asynchronous indexing" +"Orders and Returns Search Form","Orders and Returns Search Form" +"Anchor Custom Title","Anchor Custom Title" Template,Template -Default Template,Default Template +"Default Template","Default Template" Name,Name Phone,Phone -ZIP/Post Code,ZIP/Post Code -Signed-up Point,Signed-up Point +"ZIP/Post Code","ZIP/Post Code" +"Signed-up Point","Signed-up Point" Website,Website -Bill-to Name,Bill-to Name +"Bill-to Name","Bill-to Name" Created,Created -Invoice Date,Invoice Date -Ship-to Name,Ship-to Name -Ship Date,Ship Date -Total Quantity,Total Quantity -Default Status,Default Status -State Code and Title,State Code and Title -Item Status,Item Status -Original Price,Original Price -Tax Percent,Tax Percent -All Store Views,All Store Views -PDF Credit Memos,PDF Credit Memos -Purchase Point,Purchase Point -Print Invoices,Print Invoices -Print Packing Slips,Print Packing Slips -Print Credit Memos,Print Credit Memos -Print All,Print All -Print Shipping Labels,Print Shipping Labels -Purchase Date,Purchase Date -Grand Total (Base),Grand Total (Base) -Grand Total (Purchased),Grand Total (Purchased) -Customer Email,Customer Email -Shipping and Handling,Shipping and Handling -PDF Invoices,PDF Invoices -PDF Shipments,PDF Shipments -PDF Creditmemos,PDF Creditmemos +"Invoice Date","Invoice Date" +"Ship-to Name","Ship-to Name" +"Ship Date","Ship Date" +"Total Quantity","Total Quantity" +"Default Status","Default Status" +"State Code and Title","State Code and Title" +"Item Status","Item Status" +"Original Price","Original Price" +"Tax Percent","Tax Percent" +"All Store Views","All Store Views" +"PDF Credit Memos","PDF Credit Memos" +"Purchase Point","Purchase Point" +"Print Invoices","Print Invoices" +"Print Packing Slips","Print Packing Slips" +"Print Credit Memos","Print Credit Memos" +"Print All","Print All" +"Print Shipping Labels","Print Shipping Labels" +"Purchase Date","Purchase Date" +"Grand Total (Base)","Grand Total (Base)" +"Grand Total (Purchased)","Grand Total (Purchased)" +"Customer Email","Customer Email" +"Shipping and Handling","Shipping and Handling" +"PDF Invoices","PDF Invoices" +"PDF Shipments","PDF Shipments" +"PDF Creditmemos","PDF Creditmemos" Refunds,Refunds -Allow Zero GrandTotal for Creditmemo,Allow Zero GrandTotal for Creditmemo -Allow Zero GrandTotal,Allow Zero GrandTotal +"Allow Zero GrandTotal for Creditmemo","Allow Zero GrandTotal for Creditmemo" +"Allow Zero GrandTotal","Allow Zero GrandTotal" Email is required field for Admin order creation,Email is required field for Admin order creation If set YES Email field will be required during Admin order creation for new Customer.,If set YES Email field will be required during Admin order creation for new Customer. -Could not save the shipment tracking,Could not save the shipment tracking -Please enter a coupon code!,Please enter a coupon code! -Reorder is not available.,Reorder is not available. -The coupon code has been removed.,The coupon code has been removed. -This creditmemo no longer exists.,This creditmemo no longer exists. +"Could not save the shipment tracking","Could not save the shipment tracking" +"Please enter a coupon code!","Please enter a coupon code!" +"Reorder is not available.","Reorder is not available." +"The coupon code has been removed.","The coupon code has been removed." +"This creditmemo no longer exists.","This creditmemo no longer exists." From 7006a96ab964cdce624ff95620fa93d83754683d Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Fri, 27 Nov 2020 13:37:35 +0200 Subject: [PATCH 125/346] revert i18n shipping changes --- app/code/Magento/Shipping/i18n/en_US.csv | 262 +++++++++++------------ 1 file changed, 131 insertions(+), 131 deletions(-) diff --git a/app/code/Magento/Shipping/i18n/en_US.csv b/app/code/Magento/Shipping/i18n/en_US.csv index 831c361382490..0989f1bab4a3d 100644 --- a/app/code/Magento/Shipping/i18n/en_US.csv +++ b/app/code/Magento/Shipping/i18n/en_US.csv @@ -1,180 +1,180 @@ -New Shipment for Order #%1,New Shipment for Order #%1 -Submit Shipment,Submit Shipment -You are trying to add a quantity for some products that doesn't match the quantity that was shipped.,You are trying to add a quantity for some products that doesn't match the quantity that was shipped. -Products should be added to package(s),Products should be added to package(s) -The value that you entered is not valid.,The value that you entered is not valid. -Add Tracking Number,Add Tracking Number -Custom Value,Custom Value +"New Shipment for Order #%1","New Shipment for Order #%1" +"Submit Shipment","Submit Shipment" +"You are trying to add a quantity for some products that doesn't match the quantity that was shipped.","You are trying to add a quantity for some products that doesn't match the quantity that was shipped." +"Products should be added to package(s)","Products should be added to package(s)" +"The value that you entered is not valid.","The value that you entered is not valid." +"Add Tracking Number","Add Tracking Number" +"Custom Value","Custom Value" Add,Add -Send Tracking Information,Send Tracking Information -Are you sure you want to send a Shipment email to customer?,Are you sure you want to send a Shipment email to customer? +"Send Tracking Information","Send Tracking Information" +"Are you sure you want to send a Shipment email to customer?","Are you sure you want to send a Shipment email to customer?" Print,Print -the shipment email was sent,the shipment email was sent -the shipment email is not sent,the shipment email is not sent -Shipment #%1 | %3 (%2),Shipment #%1 | %3 (%2) -Create Shipping Label...,Create Shipping Label... -Print Shipping Label,Print Shipping Label -Show Packages,Show Packages -About Your Shipment,About Your Shipment -Order # %1,Order # %1 -Back to My Orders,Back to My Orders -View Another Order,View Another Order -Please enter a comment.,Please enter a comment. -Cannot add new comment.,Cannot add new comment. -Please specify a carrier.,Please specify a carrier. -Please enter a tracking number.,Please enter a tracking number. +"the shipment email was sent","the shipment email was sent" +"the shipment email is not sent","the shipment email is not sent" +"Shipment #%1 | %3 (%2)","Shipment #%1 | %3 (%2)" +"Create Shipping Label...","Create Shipping Label..." +"Print Shipping Label","Print Shipping Label" +"Show Packages","Show Packages" +"About Your Shipment","About Your Shipment" +"Order # %1","Order # %1" +"Back to My Orders","Back to My Orders" +"View Another Order","View Another Order" +"Please enter a comment.","Please enter a comment." +"Cannot add new comment.","Cannot add new comment." +"Please specify a carrier.","Please specify a carrier." +"Please enter a tracking number.","Please enter a tracking number." Shipments,Shipments -We can't initialize shipment for adding tracking number.,We can't initialize shipment for adding tracking number. -Cannot add tracking number.,Cannot add tracking number. -You created the shipping label.,You created the shipping label. -An error occurred while creating shipping label.,An error occurred while creating shipping label. -You sent the shipment.,You sent the shipment. -Cannot send shipment information.,Cannot send shipment information. -There are no shipping labels related to selected orders.,There are no shipping labels related to selected orders. -New Shipment,New Shipment -We don't recognize or support the file extension in this shipment: %1.,We don't recognize or support the file extension in this shipment: %1. -We can't initialize shipment for delete tracking number.,We can't initialize shipment for delete tracking number. -We can't delete tracking number.,We can't delete tracking number. -We can't load track with retrieving identifier right now.,We can't load track with retrieving identifier right now. -We can't save the shipment right now.,We can't save the shipment right now. +"We can't initialize shipment for adding tracking number.","We can't initialize shipment for adding tracking number." +"Cannot add tracking number.","Cannot add tracking number." +"You created the shipping label.","You created the shipping label." +"An error occurred while creating shipping label.","An error occurred while creating shipping label." +"You sent the shipment.","You sent the shipment." +"Cannot send shipment information.","Cannot send shipment information." +"There are no shipping labels related to selected orders.","There are no shipping labels related to selected orders." +"New Shipment","New Shipment" +"We don't recognize or support the file extension in this shipment: %1.","We don't recognize or support the file extension in this shipment: %1." +"We can't initialize shipment for delete tracking number.","We can't initialize shipment for delete tracking number." +"We can't delete tracking number.","We can't delete tracking number." +"We can't load track with retrieving identifier right now.","We can't load track with retrieving identifier right now." +"We can't save the shipment right now.","We can't save the shipment right now." """Shipment Document Validation Error(s):\n"" .","""Shipment Document Validation Error(s):\n"" ." -The shipment has been created.,The shipment has been created. -Cannot save shipment.,Cannot save shipment. -The order no longer exists.,The order no longer exists. -Cannot do shipment for the order separately from invoice.,Cannot do shipment for the order separately from invoice. -Cannot do shipment for the order.,Cannot do shipment for the order. -There are no shipping labels related to selected shipments.,There are no shipping labels related to selected shipments. -Page not found.,Page not found. -Tracking Information,Tracking Information +"The shipment has been created.","The shipment has been created." +"Cannot save shipment.","Cannot save shipment." +"The order no longer exists.","The order no longer exists." +"Cannot do shipment for the order separately from invoice.","Cannot do shipment for the order separately from invoice." +"Cannot do shipment for the order.","Cannot do shipment for the order." +"There are no shipping labels related to selected shipments.","There are no shipping labels related to selected shipments." +"Page not found.","Page not found." +"Tracking Information","Tracking Information" "Sorry, but we can't deliver to the destination country with this shipping module.","Sorry, but we can't deliver to the destination country with this shipping module." -The shipping module is not available.,The shipping module is not available. -This shipping method is not available. Please specify the zip code.,This shipping method is not available. Please specify the zip code. -No packages for request,No packages for request -Security validation of XML document has been failed.,Security validation of XML document has been failed. -All Allowed Countries,All Allowed Countries -Specific Countries,Specific Countries +"The shipping module is not available.","The shipping module is not available." +"This shipping method is not available. Please specify the zip code.","This shipping method is not available. Please specify the zip code." +"No packages for request","No packages for request" +"Security validation of XML document has been failed.","Security validation of XML document has been failed." +"All Allowed Countries","All Allowed Countries" +"Specific Countries","Specific Countries" Development,Development Live,Live -Divide to equal weight (one request),Divide to equal weight (one request) -Use origin weight (few requests),Use origin weight (few requests) +"Divide to equal weight (one request)","Divide to equal weight (one request)" +"Use origin weight (few requests)","Use origin weight (few requests)" Packages,Packages Package,Package Type,Type Length,Length -Signature Confirmation,Signature Confirmation -Customs Value,Customs Value +"Signature Confirmation","Signature Confirmation" +"Customs Value","Customs Value" Width,Width Contents,Contents -Total Weight,Total Weight +"Total Weight","Total Weight" Height,Height Size,Size Girth,Girth -Items in the Package,Items in the Package +"Items in the Package","Items in the Package" Product,Product Weight,Weight -Qty Ordered,Qty Ordered +"Qty Ordered","Qty Ordered" Qty,Qty "No detail for number ""%1""","No detail for number ""%1""" -Shipping labels is not available.,Shipping labels is not available. -Response info is not exist.,Response info is not exist. -Invalid carrier: %1,Invalid carrier: %1 -We don't have enough information to create shipping labels. Please make sure your store information and settings are complete.,We don't have enough information to create shipping labels. Please make sure your store information and settings are complete. -Per Order,Per Order -Per Package,Per Package +"Shipping labels is not available.","Shipping labels is not available." +"Response info is not exist.","Response info is not exist." +"Invalid carrier: %1","Invalid carrier: %1" +"We don't have enough information to create shipping labels. Please make sure your store information and settings are complete.","We don't have enough information to create shipping labels. Please make sure your store information and settings are complete." +"Per Order","Per Order" +"Per Package","Per Package" Fixed,Fixed Percent,Percent -Tracking information is unavailable.,Tracking information is unavailable. +"Tracking information is unavailable.","Tracking information is unavailable." message,message -Email has not been sent,Email has not been sent -Payment & Shipping Method,Payment & Shipping Method -Payment Information,Payment Information -The order was placed using %1.,The order was placed using %1. -Shipping Information,Shipping Information -Total Shipping Charges,Total Shipping Charges -Incl. Tax,Incl. Tax -Items to Ship,Items to Ship -Qty to Ship,Qty to Ship +"Email has not been sent","Email has not been sent" +"Payment & Shipping Method","Payment & Shipping Method" +"Payment Information","Payment Information" +"The order was placed using %1.","The order was placed using %1." +"Shipping Information","Shipping Information" +"Total Shipping Charges","Total Shipping Charges" +"Incl. Tax","Incl. Tax" +"Items to Ship","Items to Ship" +"Qty to Ship","Qty to Ship" Ship,Ship -Shipment Total,Shipment Total -Shipment Comments,Shipment Comments -Comment Text,Comment Text -Shipment Options,Shipment Options -Create Shipping Label,Create Shipping Label -Append Comments,Append Comments -Email Copy of Shipment,Email Copy of Shipment -Invalid value(s) for Qty to Ship,Invalid value(s) for Qty to Ship -Select All,Select All -Product Name,Product Name +"Shipment Total","Shipment Total" +"Shipment Comments","Shipment Comments" +"Comment Text","Comment Text" +"Shipment Options","Shipment Options" +"Create Shipping Label","Create Shipping Label" +"Append Comments","Append Comments" +"Email Copy of Shipment","Email Copy of Shipment" +"Invalid value(s) for Qty to Ship","Invalid value(s) for Qty to Ship" +"Select All","Select All" +"Product Name","Product Name" Delete,Delete -Create Packages,Create Packages +"Create Packages","Create Packages" Cancel,Cancel Save,Save -Add Package,Add Package -Add Selected Product(s) to Package,Add Selected Product(s) to Package -Add Products to Package,Add Products to Package -USPS domestic shipments don't use package types.,USPS domestic shipments don't use package types. +"Add Package","Add Package" +"Add Selected Product(s) to Package","Add Selected Product(s) to Package" +"Add Products to Package","Add Products to Package" +"USPS domestic shipments don't use package types.","USPS domestic shipments don't use package types." in,in cm,cm lb,lb kg,kg -Delete Package,Delete Package +"Delete Package","Delete Package" Explanation,Explanation Carrier,Carrier Title,Title Number,Number Action,Action -Are you sure?,Are you sure? -Shipping & Handling Information,Shipping & Handling Information -Track Order,Track Order -No shipping information available,No shipping information available -Shipping and Tracking Information,Shipping and Tracking Information -Track this shipment,Track this shipment -Items Shipped,Items Shipped -Order Total,Order Total -Shipment History,Shipment History -Qty Shipped,Qty Shipped -Print All Shipments,Print All Shipments -Shipment #,Shipment # -Print Shipment,Print Shipment -Tracking Number(s):,Tracking Number(s): +"Are you sure?","Are you sure?" +"Shipping & Handling Information","Shipping & Handling Information" +"Track Order","Track Order" +"No shipping information available","No shipping information available" +"Shipping and Tracking Information","Shipping and Tracking Information" +"Track this shipment","Track this shipment" +"Items Shipped","Items Shipped" +"Order Total","Order Total" +"Shipment History","Shipment History" +"Qty Shipped","Qty Shipped" +"Print All Shipments","Print All Shipments" +"Shipment #","Shipment #" +"Print Shipment","Print Shipment" +"Tracking Number(s):","Tracking Number(s):" SKU,SKU -Order tracking,Order tracking -Tracking Number:,Tracking Number: +"Order tracking","Order tracking" +"Tracking Number:","Tracking Number:" Carrier:,Carrier: Error:,Error: -Tracking information is currently not available. Please ,Tracking information is currently not available. Please -contact us,contact us - for more information or , for more information or -email us at ,email us at +"Tracking information is currently not available. Please ","Tracking information is currently not available. Please " +"contact us","contact us" +" for more information or "," for more information or " +"email us at ","email us at " Info:,Info: Track:,Track: -. ':',. ':' -Delivered on:,Delivered on: +". ':'",". ':'" +"Delivered on:","Delivered on:" N/A,N/A -There is no tracking available for this shipment.,There is no tracking available for this shipment. -There is no tracking available.,There is no tracking available. -Close Window,Close Window -Track history,Track history +"There is no tracking available for this shipment.","There is no tracking available for this shipment." +"There is no tracking available.","There is no tracking available." +"Close Window","Close Window" +"Track history","Track history" Location,Location Date,Date -Local Time,Local Time +"Local Time","Local Time" Description,Description -See our Shipping Policy,See our Shipping Policy -Shipping Settings Section,Shipping Settings Section -Shipping Policy Parameters Section,Shipping Policy Parameters Section -Shipping Methods Section,Shipping Methods Section -Shipping Settings,Shipping Settings +"See our Shipping Policy","See our Shipping Policy" +"Shipping Settings Section","Shipping Settings Section" +"Shipping Policy Parameters Section","Shipping Policy Parameters Section" +"Shipping Methods Section","Shipping Methods Section" +"Shipping Settings","Shipping Settings" Origin,Origin Country,Country Region/State,Region/State -ZIP/Postal Code,ZIP/Postal Code +"ZIP/Postal Code","ZIP/Postal Code" City,City -Street Address,Street Address -Street Address Line 2,Street Address Line 2 -Shipping Policy Parameters,Shipping Policy Parameters -Apply custom Shipping Policy,Apply custom Shipping Policy -Shipping Policy,Shipping Policy -Shipping Methods,Shipping Methods -Track your order,Track your order -Track All Shipments,Track All Shipments -This shipment no longer exists.,This shipment no longer exists. +"Street Address","Street Address" +"Street Address Line 2","Street Address Line 2" +"Shipping Policy Parameters","Shipping Policy Parameters" +"Apply custom Shipping Policy","Apply custom Shipping Policy" +"Shipping Policy","Shipping Policy" +"Shipping Methods","Shipping Methods" +"Track your order","Track your order" +"Track All Shipments","Track All Shipments" +"This shipment no longer exists.","This shipment no longer exists." From c6aaabc206c335ca9235ff84a403f9d6ac937ebc Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transoftgroup.com> Date: Fri, 27 Nov 2020 16:36:52 +0200 Subject: [PATCH 126/346] MC-38822: Attributes position doesn't affect the ranking in graphql response --- .../Plugin/Search/Request/ConfigReader.php | 3 + .../CategoryAggregationsTest.php | 56 ++++++ ...cts_with_layered_navigation_attributes.php | 165 ++++++++++++++++++ ...layered_navigation_attributes_rollback.php | 63 +++++++ 4 files changed, 287 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoriesQuery/CategoryAggregationsTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes_rollback.php diff --git a/app/code/Magento/CatalogGraphQl/Plugin/Search/Request/ConfigReader.php b/app/code/Magento/CatalogGraphQl/Plugin/Search/Request/ConfigReader.php index 992ab50467c72..b61ecfff4e3f1 100644 --- a/app/code/Magento/CatalogGraphQl/Plugin/Search/Request/ConfigReader.php +++ b/app/code/Magento/CatalogGraphQl/Plugin/Search/Request/ConfigReader.php @@ -106,6 +106,9 @@ private function getSearchableAttributes(): array $productAttributes->addFieldToFilter( ['is_searchable', 'is_visible_in_advanced_search', 'is_filterable', 'is_filterable_in_search'], [1, 1, [1, 2], 1] + )->setOrder( + 'position', + 'ASC' ); /** @var Attribute $attribute */ diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoriesQuery/CategoryAggregationsTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoriesQuery/CategoryAggregationsTest.php new file mode 100644 index 0000000000000..a0f184507a9aa --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoriesQuery/CategoryAggregationsTest.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Catalog\CategoriesQuery; + +use Magento\TestFramework\TestCase\GraphQlAbstract; + +/** + * Test to return category aggregations + */ +class CategoryAggregationsTest extends GraphQlAbstract +{ + /** + * Test to return category aggregations in sorting by position + * + * @magentoApiDataFixture Magento/Catalog/_files/products_with_layered_navigation_attributes.php + */ + public function testCategoryAggregationSorting(): void + { + $categoryId = 3334; + $query = <<<QUERY +{ + products(filter: {category_id: {eq: "{$categoryId}"}}) { + aggregations{ + label + attribute_code + count + options{ + label + value + count + } + } + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $response); + $this->assertArrayHasKey('products', $response); + $this->assertArrayHasKey('aggregations', $response['products']); + + $customAggregation = array_values(array_filter( + $response['products']['aggregations'], + function ($a) { + return in_array($a['attribute_code'], ['test_attribute_1', 'test_attribute_2']); + } + )); + $this->assertCount(2, $customAggregation); + $this->assertEquals('test_attribute_2', $customAggregation[0]['attribute_code']); + $this->assertEquals('test_attribute_1', $customAggregation[1]['attribute_code']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes.php new file mode 100644 index 0000000000000..8764e12916d8b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes.php @@ -0,0 +1,165 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\Data\CategoryInterfaceFactory; +use Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory; +use Magento\Catalog\Api\Data\ProductInterfaceFactory; +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Eav\Model\Config; +use Magento\Eav\Setup\EavSetup; +use Magento\Indexer\Model\Indexer; +use Magento\Indexer\Model\Indexer\Collection; +use Magento\Msrp\Model\Product\Attribute\Source\Type as SourceType; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\CacheCleaner; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var Config $eavConfig */ +$eavConfig = $objectManager->get(Config::class); + +/** @var ProductAttributeRepositoryInterface $attributeRepository */ +$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class); +/** @var ProductAttributeInterfaceFactory $attributeFactory */ +$attributeFactory = $objectManager->get(ProductAttributeInterfaceFactory::class); + +/** @var $installer EavSetup */ +$installer = $objectManager->get(EavSetup::class); +$attributeSetId = $installer->getAttributeSetId(Product::ENTITY, 'Default'); +$groupId = $installer->getDefaultAttributeGroupId(Product::ENTITY, $attributeSetId); + +/** @var WebsiteRepositoryInterface $websiteRepository */ +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$baseWebsite = $websiteRepository->get('base'); + +for ($i = 1; $i <= 2; $i++) { + $attributeModel = $attributeFactory->create(); + $attributeModel->setData( + [ + 'attribute_code' => 'test_attribute_' . $i, + 'entity_type_id' => $installer->getEntityTypeId(Product::ENTITY), + 'is_global' => 1, + 'is_user_defined' => 1, + 'frontend_input' => 'select', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 1, + 'is_visible_in_advanced_search' => 1, + 'is_comparable' => 1, + 'is_filterable' => 1, + 'is_filterable_in_search' => 1, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 1, + 'used_in_product_listing' => 1, + 'used_for_sort_by' => 1, + 'frontend_label' => ['Test Attribute ' . $i], + 'backend_type' => 'int', + 'option' => [ + 'value' => ['option_0' => ['Option 1'], 'option_1' => ['Option 2']], + 'order' => ['option_0' => 1, 'option_1' => 2], + ], + 'default' => ['option_0'], + 'position' => 3 - $i + ] + ); + $attribute = $attributeRepository->save($attributeModel); + $installer->addAttributeToGroup(Product::ENTITY, $attributeSetId, $groupId, $attribute->getId()); +} + +CacheCleaner::cleanAll(); +$eavConfig->clear(); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var ProductInterfaceFactory $productInterfaceFactory */ +$productInterfaceFactory = $objectManager->get(ProductInterfaceFactory::class); + +/** @var Product $product */ +$product = $productInterfaceFactory->create(); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setName('Simple Product1') + ->setSku('simple1') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(SourceType::TYPE_IN_CART) + ->setPrice(10) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setWebsiteIds([$baseWebsite->getId()]) + ->setCategoryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setSpecialPrice('5.99'); +$simple1 = $productRepository->save($product); + +/** @var Product $product */ +$product = $productInterfaceFactory->create(); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setName('Simple Product2') + ->setSku('simple2') + ->setTaxClassId('none') + ->setDescription('description') + ->setShortDescription('short description') + ->setOptionsContainer('container1') + ->setMsrpDisplayActualPriceType(SourceType::TYPE_ON_GESTURE) + ->setPrice(20) + ->setWeight(1) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setWebsiteIds([$baseWebsite->getId()]) + ->setCategoryIds([]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 50, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setSpecialPrice('15.99'); +$simple2 = $productRepository->save($product); + +/** @var CategoryInterfaceFactory $categoryInterfaceFactory */ +$categoryInterfaceFactory = $objectManager->get(CategoryInterfaceFactory::class); + +$category = $categoryInterfaceFactory->create(); +$category->isObjectNew(true); +$category->setId(3334) + ->setCreatedAt('2014-06-23 09:50:07') + ->setName('Category 1') + ->setParentId(2) + ->setPath('1/2/333') + ->setLevel(2) + ->setAvailableSortBy(['position', 'name']) + ->setDefaultSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setPostedProducts( + [ + $simple1->getId() => 10, + $simple2->getId() => 11 + ] + ); +$category->save(); + +/** @var Collection $indexerCollection */ +$indexerCollection = $objectManager->get(Collection::class); +$indexerCollection->load(); +/** @var Indexer $indexer */ +foreach ($indexerCollection->getItems() as $indexer) { + $indexer->reindexAll(); +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes_rollback.php new file mode 100644 index 0000000000000..49e2b549552e6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_with_layered_navigation_attributes_rollback.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Eav\Model\Config; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Registry; +use Magento\TestFramework\Catalog\Model\GetCategoryByName; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); + +foreach (['simple1', 'simple2'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + $productRepository->delete($product); + } catch (NoSuchEntityException $exception) { + //Product already removed + } +} + +/** @var CategoryRepositoryInterface $categoryRepository */ +$categoryRepository = $objectManager->get(CategoryRepositoryInterface::class); +/** @var GetCategoryByName $getCategoryByName */ +$getCategoryByName = $objectManager->get(GetCategoryByName::class); +$category = $getCategoryByName->execute('Category 1'); +try { + if ($category->getId()) { + $categoryRepository->delete($category); + } +} catch (NoSuchEntityException $exception) { + //Category already removed +} + +$eavConfig = $objectManager->get(Config::class); +/** @var ProductAttributeRepositoryInterface $attributeRepository */ +$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class); + +try { + for ($i = 1; $i <= 2; $i++) { + $attribute = $attributeRepository->get('test_attribute_' . $i); + $attributeRepository->delete($attribute); + } +} catch (NoSuchEntityException $exception) { + //Attribute already removed +} +$eavConfig->clear(); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From e567fd6c343cd383bc58b8b6b8b90b45844ded7d Mon Sep 17 00:00:00 2001 From: TuNa <ladiesman9x@gmail.com> Date: Fri, 27 Nov 2020 21:51:16 +0700 Subject: [PATCH 127/346] Fix minisearch not appear when disable suggestions search update up up up up up update update update up update update testCaseId --- .../Section/StorefrontQuickSearchSection.xml | 1 + ...ldVisibilityWhenSuggestionDisabledTest.xml | 54 +++++++++ .../Search/ViewModel/ConfigProvider.php | 21 +++- .../view/frontend/templates/form.mini.phtml | 44 +++---- .../Search/view/frontend/web/js/form-mini.js | 113 +++++++++--------- 5 files changed, 156 insertions(+), 77 deletions(-) create mode 100644 app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchFieldVisibilityWhenSuggestionDisabledTest.xml diff --git a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml index 34379fd6d2e4a..088bd5eed4cc3 100644 --- a/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml +++ b/app/code/Magento/Search/Test/Mftf/Section/StorefrontQuickSearchSection.xml @@ -14,5 +14,6 @@ <element name="searchMiniForm" type="input" selector="#search_mini_form"/> <element name="searchDropDownSuggestion" type="text" selector="//div[@id='search_autocomplete']/ul/li/span"/> <element name="searchDropDownName" type="text" selector="//div[@id='search_autocomplete']//span[contains(., '{{searchQuery}}')]" parameterized="true"/> + <element name="searchMagnifierIcon" type="text" selector="//*[@id='search_mini_form']//label[@data-role='minisearch-label']"/> </section> </sections> diff --git a/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchFieldVisibilityWhenSuggestionDisabledTest.xml b/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchFieldVisibilityWhenSuggestionDisabledTest.xml new file mode 100644 index 0000000000000..cdd52bd2b524e --- /dev/null +++ b/app/code/Magento/Search/Test/Mftf/Test/StorefrontVerifySearchFieldVisibilityWhenSuggestionDisabledTest.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontVerifySearchFieldVisibilityWhenSuggestionDisabledTest"> + <annotations> + <stories value="Search Term"/> + <title value="Mini search field appears if suggestions was disabled"/> + <description value="Mini search field appears if suggestions was disabled"/> + <severity value="AVERAGE"/> + <testCaseId value="MC-39443"/> + <group value="mtf_migrated"/> + </annotations> + + <before> + <!-- Login as admin --> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <!-- Disable search suggestion --> + <magentoCLI command="config:set catalog/search/search_suggestion_enabled 0" stepKey="disableSearchSuggestion"/> + + <actionGroup ref="CliCacheCleanActionGroup" stepKey="cleanCacheFirst"> + <argument name="tags" value="config full_page"/> + </actionGroup> + </before> + + <after> + <!-- Enable search suggestion back --> + <magentoCLI command="config:set catalog/search/search_suggestion_enabled 1" stepKey="disableSearchSuggestion"/> + + <actionGroup ref="CliCacheCleanActionGroup" stepKey="cleanCacheSecond"> + <argument name="tags" value="config full_page"/> + </actionGroup> + + <!-- Admin logout --> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <!-- Go to storefront home page --> + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="openStoreFrontHomePage"/> + + <resizeWindow width="767" height="720" stepKey="resizeWindowToMobileView"/> + + <click selector="{{StorefrontQuickSearchSection.searchMagnifierIcon}}" stepKey="clickOnMagnifierSearchIcon"/> + + <waitForElementVisible selector="{{StorefrontQuickSearchSection.searchPhrase}}" after="clickOnMagnifierSearchIcon" stepKey="seeInputSearchActive"/> + + </test> +</tests> diff --git a/app/code/Magento/Search/ViewModel/ConfigProvider.php b/app/code/Magento/Search/ViewModel/ConfigProvider.php index be3366e62e965..b1db5b57e13e0 100644 --- a/app/code/Magento/Search/ViewModel/ConfigProvider.php +++ b/app/code/Magento/Search/ViewModel/ConfigProvider.php @@ -10,6 +10,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\View\Element\Block\ArgumentInterface; use Magento\Store\Model\ScopeInterface; +use Magento\Search\Helper\Data as SearchHelper; /** * View model for search @@ -26,13 +27,31 @@ class ConfigProvider implements ArgumentInterface */ private $scopeConfig; + /** + * @var SearchHelper + */ + private $searchHelper; + /** * @param ScopeConfigInterface $scopeConfig + * @param SearchHelper $searchHelper */ public function __construct( - ScopeConfigInterface $scopeConfig + ScopeConfigInterface $scopeConfig, + SearchHelper $searchHelper ) { $this->scopeConfig = $scopeConfig; + $this->searchHelper = $searchHelper; + } + + /** + * Retrieve search helper instance for template view + * + * @return SearchHelper + */ + public function getSearchHelperData(): SearchHelper + { + return $this->searchHelper; } /** diff --git a/app/code/Magento/Search/view/frontend/templates/form.mini.phtml b/app/code/Magento/Search/view/frontend/templates/form.mini.phtml index 80e720e2c2fe2..c6b2a6a729575 100644 --- a/app/code/Magento/Search/view/frontend/templates/form.mini.phtml +++ b/app/code/Magento/Search/view/frontend/templates/form.mini.phtml @@ -4,40 +4,42 @@ * See COPYING.txt for license details. */ -// phpcs:disable Magento2.Templates.ThisInTemplate.FoundThis ?> <?php /** @var $block \Magento\Framework\View\Element\Template */ -/** @var $helper \Magento\Search\Helper\Data */ +/** @var $escaper \Magento\Framework\Escaper */ /** @var $configProvider \Magento\Search\ViewModel\ConfigProvider */ -$helper = $this->helper(\Magento\Search\Helper\Data::class); $configProvider = $block->getData('configProvider'); +/** @var $helper \Magento\Search\Helper\Data */ +$helper = $configProvider->getSearchHelperData(); +$allowedSuggestion = $configProvider->isSuggestionsAllowed(); +$quickSearchUrl = $allowedSuggestion ? $escaper->escapeUrl($helper->getSuggestUrl()) : ''; ?> <div class="block block-search"> - <div class="block block-title"><strong><?= $block->escapeHtml(__('Search')) ?></strong></div> + <div class="block block-title"><strong><?= $escaper->escapeHtml(__('Search')) ?></strong></div> <div class="block block-content"> <form class="form minisearch" id="search_mini_form" - action="<?= $block->escapeUrl($helper->getResultUrl()) ?>" method="get"> + action="<?= $escaper->escapeUrl($helper->getResultUrl()) ?>" method="get"> <div class="field search"> <label class="label" for="search" data-role="minisearch-label"> - <span><?= $block->escapeHtml(__('Search')) ?></span> + <span><?= $escaper->escapeHtml(__('Search')) ?></span> </label> <div class="control"> <input id="search" - <?php if ($configProvider->isSuggestionsAllowed()):?> - data-mage-init='{"quickSearch":{ - "formSelector":"#search_mini_form", - "url":"<?= $block->escapeUrl($helper->getSuggestUrl())?>", - "destinationSelector":"#search_autocomplete", - "minSearchLength":"<?= $block->escapeHtml($helper->getMinQueryLength()) ?>"} - }' - <?php endif;?> + data-mage-init='{ + "quickSearch": { + "formSelector": "#search_mini_form", + "url": "<?= /* @noEscape */ $quickSearchUrl ?>", + "destinationSelector": "#search_autocomplete", + "minSearchLength": "<?= $escaper->escapeHtml($helper->getMinQueryLength()) ?>" + } + }' type="text" - name="<?= $block->escapeHtmlAttr($helper->getQueryParamName()) ?>" + name="<?= $escaper->escapeHtmlAttr($helper->getQueryParamName()) ?>" value="<?= /* @noEscape */ $helper->getEscapedQueryText() ?>" - placeholder="<?= $block->escapeHtmlAttr(__('Search entire store here...')) ?>" + placeholder="<?= $escaper->escapeHtmlAttr(__('Search entire store here...')) ?>" class="input-text" - maxlength="<?= $block->escapeHtmlAttr($helper->getMaxQueryLength()) ?>" + maxlength="<?= $escaper->escapeHtmlAttr($helper->getMaxQueryLength()) ?>" role="combobox" aria-haspopup="false" aria-autocomplete="both" @@ -49,11 +51,11 @@ $configProvider = $block->getData('configProvider'); </div> <div class="actions"> <button type="submit" - title="<?= $block->escapeHtml(__('Search')) ?>" - class="action search" - aria-label="Search" + title="<?= $escaper->escapeHtml(__('Search')) ?>" + class="action search" + aria-label="Search" > - <span><?= $block->escapeHtml(__('Search')) ?></span> + <span><?= $escaper->escapeHtml(__('Search')) ?></span> </button> </div> </form> diff --git a/app/code/Magento/Search/view/frontend/web/js/form-mini.js b/app/code/Magento/Search/view/frontend/web/js/form-mini.js index 9b4c814f73d73..b8034fead76d0 100644 --- a/app/code/Magento/Search/view/frontend/web/js/form-mini.js +++ b/app/code/Magento/Search/view/frontend/web/js/form-mini.js @@ -35,12 +35,12 @@ define([ selectClass: 'selected', template: '<li class="<%- data.row_class %>" id="qs-option-<%- data.index %>" role="option">' + - '<span class="qs-option-name">' + - ' <%- data.title %>' + - '</span>' + - '<span aria-hidden="true" class="amount">' + - '<%- data.num_results %>' + - '</span>' + + '<span class="qs-option-name">' + + ' <%- data.title %>' + + '</span>' + + '<span aria-hidden="true" class="amount">' + + '<%- data.num_results %>' + + '</span>' + '</li>', submitBtn: 'button[type="submit"]', searchLabel: '[data-role=minisearch-label]', @@ -300,60 +300,63 @@ define([ if (value.length >= parseInt(this.options.minSearchLength, 10)) { this.submitBtn.disabled = false; - $.getJSON(this.options.url, { - q: value - }, $.proxy(function (data) { - if (data.length) { - $.each(data, function (index, element) { - var html; - - element.index = index; - html = template({ - data: element - }); - dropdown.append(html); - }); - - this._resetResponseList(true); - this.responseList.indexList = this.autoComplete.html(dropdown) - .css(clonePosition) - .show() - .find(this.options.responseFieldElements + ':visible'); - - this.element.removeAttr('aria-activedescendant'); + if (this.options.url !== '') { //eslint-disable-line eqeqeq + $.getJSON(this.options.url, { + q: value + }, $.proxy(function (data) { + if (data.length) { + $.each(data, function (index, element) { + var html; + + element.index = index; + html = template({ + data: element + }); + dropdown.append(html); + }); - if (this.responseList.indexList.length) { - this._updateAriaHasPopup(true); + this._resetResponseList(true); + + this.responseList.indexList = this.autoComplete.html(dropdown) + .css(clonePosition) + .show() + .find(this.options.responseFieldElements + ':visible'); + + this.element.removeAttr('aria-activedescendant'); + + if (this.responseList.indexList.length) { + this._updateAriaHasPopup(true); + } else { + this._updateAriaHasPopup(false); + } + + this.responseList.indexList + .on('click', function (e) { + this.responseList.selected = $(e.currentTarget); + this.searchForm.trigger('submit'); + }.bind(this)) + .on('mouseenter mouseleave', function (e) { + this.responseList.indexList.removeClass(this.options.selectClass); + $(e.target).addClass(this.options.selectClass); + this.responseList.selected = $(e.target); + this.element.attr('aria-activedescendant', $(e.target).attr('id')); + }.bind(this)) + .on('mouseout', function (e) { + if (!this._getLastElement() && + this._getLastElement().hasClass(this.options.selectClass)) { + $(e.target).removeClass(this.options.selectClass); + this._resetResponseList(false); + } + }.bind(this)); } else { + this._resetResponseList(true); + this.autoComplete.hide(); this._updateAriaHasPopup(false); + this.element.removeAttr('aria-activedescendant'); } - - this.responseList.indexList - .on('click', function (e) { - this.responseList.selected = $(e.currentTarget); - this.searchForm.trigger('submit'); - }.bind(this)) - .on('mouseenter mouseleave', function (e) { - this.responseList.indexList.removeClass(this.options.selectClass); - $(e.target).addClass(this.options.selectClass); - this.responseList.selected = $(e.target); - this.element.attr('aria-activedescendant', $(e.target).attr('id')); - }.bind(this)) - .on('mouseout', function (e) { - if (!this._getLastElement() && - this._getLastElement().hasClass(this.options.selectClass)) { - $(e.target).removeClass(this.options.selectClass); - this._resetResponseList(false); - } - }.bind(this)); - } else { - this._resetResponseList(true); - this.autoComplete.hide(); - this._updateAriaHasPopup(false); - this.element.removeAttr('aria-activedescendant'); - } - }, this)); + }, this)); + } } else { this._resetResponseList(true); this.autoComplete.hide(); From 30ac6b5bd5fba5782498aba9b59eb096eebb44c8 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Sat, 28 Nov 2020 17:32:49 -0600 Subject: [PATCH 128/346] MC-38900: GraphQL Mutation setGuestEmailOnCart doesn't update quote address --- .../Quote/Guest/SetGuestEmailOnCartTest.php | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php index 7a14aca72d83f..ccafe5669e526 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php @@ -8,6 +8,9 @@ namespace Magento\GraphQl\Quote\Guest; use Magento\GraphQl\Quote\GetMaskedQuoteIdByReservedOrderId; +use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\QuoteFactory; +use Magento\Quote\Model\ResourceModel\Quote as QuoteResource; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; @@ -21,10 +24,22 @@ class SetGuestEmailOnCartTest extends GraphQlAbstract */ private $getMaskedQuoteIdByReservedOrderId; + /** + * @var QuoteFactory + */ + private $quoteFactory; + + /** + * @var QuoteResource + */ + private $quoteResource; + protected function setUp(): void { $objectManager = Bootstrap::getObjectManager(); $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); + $this->quoteFactory = $objectManager->get(QuoteFactory::class); + $this->quoteResource = $objectManager->get(QuoteResource::class); } /** @@ -43,6 +58,32 @@ public function testSetGuestEmailOnCart() $this->assertEquals($email, $response['setGuestEmailOnCart']['cart']['email']); } + /** + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php + */ + public function testSetGuestEmailOnCartWithDifferentEmailAddress() + { + $reservedOrderId = 'test_quote'; + $secondEmail = 'attempt2@example.com'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $email = 'attempt1@example.com'; + $query = $this->getQuery($maskedQuoteId, $email); + $this->graphQlMutation($query); + + $query = $this->getQuery($maskedQuoteId, $secondEmail); + $this->graphQlMutation($query); + + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id'); + $addresses = $quote->getAddressesCollection(); + foreach ($addresses as $address) { + if ($address->getAddressType() === Address::ADDRESS_TYPE_SHIPPING) { + $this->assertEquals($secondEmail, $address->getEmail()); + } + } + } + /** * _security * @magentoApiDataFixture Magento/Customer/_files/customer.php From 834793513617586d6f28ae039f5e5e8d3d63d7a4 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Sat, 28 Nov 2020 17:42:43 -0600 Subject: [PATCH 129/346] MC-38900: GraphQL Mutation setGuestEmailOnCart doesn't update quote address --- .../Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php index ccafe5669e526..e3c77a40a470a 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/SetGuestEmailOnCartTest.php @@ -77,6 +77,7 @@ public function testSetGuestEmailOnCartWithDifferentEmailAddress() $quote = $this->quoteFactory->create(); $this->quoteResource->load($quote, $reservedOrderId, 'reserved_order_id'); $addresses = $quote->getAddressesCollection(); + $this->assertEquals(2, $addresses->count()); foreach ($addresses as $address) { if ($address->getAddressType() === Address::ADDRESS_TYPE_SHIPPING) { $this->assertEquals($secondEmail, $address->getEmail()); From eaa4b063045cdff5b062383e92ec55e8ac9fc87e Mon Sep 17 00:00:00 2001 From: engcom-Echo <engcom-vendorworker-echo@adobe.com> Date: Mon, 30 Nov 2020 10:27:29 +0200 Subject: [PATCH 130/346] MC-37807: Link to a file of a Product with Customizable Option(File) is not available throughout a multishipping checkout process --- .../Block/Checkout/OverviewTest.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php b/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php index f4829cb614234..182505cba4a61 100644 --- a/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php +++ b/dev/tests/integration/testsuite/Magento/Multishipping/Block/Checkout/OverviewTest.php @@ -6,7 +6,7 @@ namespace Magento\Multishipping\Block\Checkout; -use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\ProductRepository; use Magento\Checkout\Block\Cart\Item\Renderer; use Magento\Framework\App\Area; use Magento\Framework\ObjectManagerInterface; @@ -26,12 +26,12 @@ class OverviewTest extends TestCase /** * @var Overview */ - protected $block; + private $block; /** * @var ObjectManagerInterface */ - protected $objectManager; + private $objectManager; /** * @var Quote @@ -39,7 +39,7 @@ class OverviewTest extends TestCase private $quote; /** - * @var Product + * @var ProductRepository */ private $product; @@ -48,6 +48,9 @@ class OverviewTest extends TestCase */ private $item; + /** + * @inheritdoc + */ protected function setUp(): void { Bootstrap::getInstance()->loadArea(Area::AREA_FRONTEND); @@ -72,9 +75,9 @@ protected function setUp(): void Renderer::class, ['template' => 'cart/item/default.phtml'] ); - $this->quote = $this->objectManager->get(Quote::class); - $this->product = $this->objectManager->get(Product::class); - $this->item = $this->objectManager->get(Item::class); + $this->quote = $this->objectManager->create(Quote::class); + $this->product = $this->objectManager->create(ProductRepository::class); + $this->item = $this->objectManager->create(Item::class); } /** @@ -82,7 +85,7 @@ protected function setUp(): void */ public function testGetRowItemHtml() { - $product = $this->product->load('1'); + $product = $this->product->get('simple'); $item = $this->item->setProduct($product); $item->setQuote($this->quote); // assure that default renderer was obtained From f36929ac2be6c65c6386325c8fc38d1d333d77b3 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 10:59:10 +0200 Subject: [PATCH 131/346] initial commit --- .../ProductsQtyReturnAfterOrderCancelTest.xml | 49 +++++++++++++------ 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml index 0b7bca201ec32..6bcf33e923080 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml @@ -8,7 +8,7 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="ProductsQtyReturnAfterOrderCancelTest"> + <test name=""> <annotations> <features value="ConfigurableProduct"/> @@ -23,28 +23,44 @@ <before> <createData entity="ApiCategory" stepKey="createCategory"/> - <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> + <createData entity="BaseConfigurableProduct" stepKey="createConfigProduct"> <requiredEntity createDataKey="createCategory"/> + <field key="quantity">1000</field> </createData> + + + <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> </before> <after> - <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> + <!-- <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> --> <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> </after> <actionGroup ref="AdminOpenCatalogProductPageActionGroup" stepKey="goToCatalogProductPage1"/> - <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> + <actionGroup ref="ClearFiltersAdminProductGridActionGroup" stepKey="clickClearFiltersInitial"/> <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct"> <argument name="product" value="$$createConfigProduct$$"/> </actionGroup> <fillField selector="{{AdminProductFormSection.productQuantity}}" userInput="100" stepKey="changeProductQuantity"/> - <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="saveChanges"/> + <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="saveChanges"/> + + <createData entity="GuestCart" stepKey="createGuestCart"/> + <createData entity="SimpleFourCartItems" stepKey="addCartItem"> + <requiredEntity createDataKey="createGuestCart"/> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddress"> + <requiredEntity createDataKey="createGuestCart"/> + </createData> + <updateData createDataKey="createGuestCart" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformation"> + <requiredEntity createDataKey="createGuestCart"/> + </updateData> - <amOnPage url="$$createConfigProduct.sku$$.html" stepKey="navigateToProductPage"/> + <!-- <amOnPage url="$$createConfigProduct.sku$$.html" stepKey="navigateToProductPage"/> <waitForPageLoad stepKey="waitForProductPage"/> <fillField selector="{{StorefrontProductInfoMainSection.qty}}" userInput="4" stepKey="fillQuantity"/> @@ -63,10 +79,10 @@ <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> </actionGroup> - <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> --> <actionGroup ref="FilterOrderGridByIdActionGroup" stepKey="filterOrderGridById"> - <argument name="orderId" value="$grabOrderNumber"/> + <argument name="orderId" value="$createGuestCart.return$"/> </actionGroup> <actionGroup ref="AdminOrderGridClickFirstRowActionGroup" stepKey="clickOrderRow"/> @@ -75,11 +91,16 @@ <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQuantity"/> <waitForPageLoad stepKey="waitPageToBeLoaded"/> <actionGroup ref="AdminInvoiceClickSubmitActionGroup" stepKey="clickSubmitInvoice"/> - <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction"/> - <waitForPageLoad stepKey="waitOrderDetailToLoad"/> - <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="1" stepKey="changeItemQtyToShip"/> - <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment"/> - <waitForPageLoad stepKey="waitShipmentSectionToLoad"/> + <!-- <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction"/> + <waitForPageLoad stepKey="waitOrderDetailToLoad"/> --> + <!-- <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="1" stepKey="changeItemQtyToShip"/> --> + <actionGroup ref="AdminCreateShipmentFromOrderPage" stepKey="clickSubmitShipment"> + <argument name="Qty" value="1"/> + <argument name="Number" value="111"/> + </actionGroup> + + <!-- <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment"/> + <waitForPageLoad stepKey="waitShipmentSectionToLoad"/> --> <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOption"> <argument name="orderStatus" value="Complete"/> </actionGroup> From c172dc17940946721a1ff28df714c7e398c2165a Mon Sep 17 00:00:00 2001 From: Nikola Lardev <nikolalardev@gmail.com> Date: Mon, 30 Nov 2020 13:35:24 +0200 Subject: [PATCH 132/346] #30959 Fix typo --- .../Directory/Setup/Patch/Data/AddDataForGreece.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php index 122a2b2bbc195..30b1021a3467d 100644 --- a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForGreece.php @@ -1,15 +1,15 @@ <?php /** - * Copyright © Magento, Inc. All rights reGRrved. - * GRe COPYING.txt for licenGR details. + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. */ declare(strict_types=1); -namespace Magento\Directory\GRtup\Patch\Data; +namespace Magento\Directory\Setup\Patch\Data; use Magento\Directory\Setup\DataInstaller; use Magento\Directory\Setup\DataInstallerFactory; -use Magento\Framework\Setup\ModuleDataGRtupInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Framework\Setup\Patch\DataPatchInterface; /** @@ -20,7 +20,7 @@ class AddDataForGreece implements DataPatchInterface /** * @var ModuleDataSetupInterface */ - private $moduleDataGRtup; + private $moduleDataSetup; /** * @var DataInstallerFactory From beac203458390fc00814f96daa19d698b0221919 Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:08:24 +0200 Subject: [PATCH 133/346] remove redundant spaces --- .../Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml index 13688afd0efe9..ce8d6414e2882 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml @@ -16,11 +16,9 @@ <severity value="MAJOR"/> <group value="shipping"/> </annotations> - <before> <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> </before> - <after> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> @@ -30,9 +28,7 @@ </actionGroup> <waitForPageLoad stepKey="waitForPageLoad"/> - <seeInCurrentUrl url="{{AdminShipmentsGridPage.url}}" stepKey="redirectToShipmentsGridPage"/> - <see selector="{{AdminMessagesSection.error}}" userInput='This shipment no longer exists.' stepKey="seeErrorMessage"/> </test> From ece8488ea87743e19e1b4b688e7395a11ebd50cf Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Mon, 30 Nov 2020 15:02:52 +0200 Subject: [PATCH 134/346] MC-36383: [B2B] A Product with Customizable Option (File) can not be added from a Requisition List to the Shopping Cart --- app/code/Magento/Catalog/Model/Product/Option/Type/File.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/File.php b/app/code/Magento/Catalog/Model/Product/Option/Type/File.php index 77ef8ef4853e1..8d35d55282a75 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Type/File.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Type/File.php @@ -228,7 +228,10 @@ public function validateUserValue($values) * previous configuration with no newly uploaded file */ $fileInfo = null; - if (isset($values[$option->getId()]) && is_array($values[$option->getId()])) { + if (isset($values[$option->getId()])) { + if (is_string($values[$option->getId()])) { + $values[$option->getId()] = explode(',', $values[$option->getId()]); + } // Legacy style, file info comes in array with option id index $fileInfo = $values[$option->getId()]; } else { From 94cdcf1827cdb4dbb04af097a668e3303bf3eede Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 16:38:33 +0200 Subject: [PATCH 135/346] Refactored ProductsQtyReturnAfterOrderCancelTest --- ...minCheckProductQtyAfterOrderCancelling.xml | 89 +++++++++++++++++++ ...nvoiceWIthUpdatedProductQtyActionGroup.xml | 23 +++++ 2 files changed, 112 insertions(+) create mode 100644 app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml new file mode 100644 index 0000000000000..8be37cccbb67a --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCheckProductQtyAfterOrderCancelling"> + + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Cancel order"/> + <title value="Product quantity return after order cancel"/> + <description value="Check Product quantity return after order cancel"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-97228"/> + <useCaseId value="MAGETWO-82221"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + + <createData entity="defaultSimpleProduct" stepKey="createConfigProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + + <createData entity="GuestCart" stepKey="createGuestCart"/> + <createData entity="FourCartItems" stepKey="addCartItem"> + <requiredEntity createDataKey="createGuestCart"/> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddress"> + <requiredEntity createDataKey="createGuestCart"/> + </createData> + <updateData createDataKey="createGuestCart" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformation"> + <requiredEntity createDataKey="createGuestCart"/> + </updateData> + + <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> + + </before> + + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> + </after> + + <actionGroup ref="FilterOrderGridByIdActionGroup" stepKey="filterOrderGridById"> + <argument name="orderId" value="$createGuestCart.return$"/> + </actionGroup> + + <actionGroup ref="AdminOrderGridClickFirstRowActionGroup" stepKey="clickOrderRow"/> + + <actionGroup ref="AdminInvoiceWIthUpdatedProductQtyActionGroup" stepKey="ChangeQtyToInvoice"> + <argument name="qty" value="1"/> + </actionGroup> + + <actionGroup ref="AdminCreateShipmentFromOrderPage" stepKey="clickSubmitShipment"> + <argument name="Qty" value="1"/> + <argument name="Number" value="111"/> + </actionGroup> + + <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOption"> + <argument name="orderStatus" value="Complete"/> + </actionGroup> + + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Canceled 3" stepKey="seeCanceledQuantity"/> + + <actionGroup ref="AdminOpenCatalogProductPageActionGroup" stepKey="goToCatalogProductPage"/> + + <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGridBySku"> + <argument name="sku" value="$$createConfigProduct.sku$$"/> + </actionGroup> + + <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="seeProductSkuInGrid"> + <argument name="row" value="1"/> + <argument name="column" value="Quantity"/> + <argument name="value" value="99"/> + </actionGroup> + + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="clearProductFilters"/> + + </test> +</tests> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml new file mode 100644 index 0000000000000..092a225c232ea --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminInvoiceWIthUpdatedProductQtyActionGroup" extends="AdminCreateInvoiceActionGroup"> + <annotations> + <description>The "Create Invoice" page: Update product qty to invoice (there is one product in the Order).</description> + </annotations> + <arguments> + <argument name="qty" type="string"/> + </arguments> + + <fillField selector="{{AdminInvoiceItemsSection.qtyToInvoiceColumn}}" userInput="{{qty}}" stepKey="changeQtyToInvoice" after="waitForInvoicePage"/> + <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQuantity" after="changeQtyToInvoice"/> + <waitForPageLoad stepKey="waitPageToBeLoaded" after="updateQuantity"/> + </actionGroup> +</actionGroups> From 0d32349f8452d84770337eda6fba4d0cce70c6ee Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 16:49:58 +0200 Subject: [PATCH 136/346] refactored --- ...minCheckProductQtyAfterOrderCancelling.xml | 4 +- .../ProductsQtyReturnAfterOrderCancelTest.xml | 49 ++++++------------- .../Quote/Test/Mftf/Data/CartItemData.xml | 5 ++ ...nvoiceWIthUpdatedProductQtyActionGroup.xml | 5 +- 4 files changed, 25 insertions(+), 38 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml index 8be37cccbb67a..71eddf6667368 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml @@ -8,7 +8,7 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AdminCheckProductQtyAfterOrderCancelling"> + <test name="AdminCheckProductQtyAfterOrderCancellingTest"> <annotations> <features value="ConfigurableProduct"/> @@ -41,7 +41,7 @@ </updateData> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> - + </before> <after> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml index 6bcf33e923080..5270c82a7e977 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml @@ -8,7 +8,7 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name=""> + <test name="ProductsQtyReturnAfterOrderCancelTest" deprecated="Use AdminCheckProductQtyAfterOrderCancellingTest instead"> <annotations> <features value="ConfigurableProduct"/> @@ -23,44 +23,28 @@ <before> <createData entity="ApiCategory" stepKey="createCategory"/> - <createData entity="BaseConfigurableProduct" stepKey="createConfigProduct"> + <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> <requiredEntity createDataKey="createCategory"/> - <field key="quantity">1000</field> </createData> - - - <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> </before> <after> - <!-- <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> --> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> </after> <actionGroup ref="AdminOpenCatalogProductPageActionGroup" stepKey="goToCatalogProductPage1"/> - <actionGroup ref="ClearFiltersAdminProductGridActionGroup" stepKey="clickClearFiltersInitial"/> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct"> <argument name="product" value="$$createConfigProduct$$"/> </actionGroup> <fillField selector="{{AdminProductFormSection.productQuantity}}" userInput="100" stepKey="changeProductQuantity"/> - <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="saveChanges"/> - - <createData entity="GuestCart" stepKey="createGuestCart"/> - <createData entity="SimpleFourCartItems" stepKey="addCartItem"> - <requiredEntity createDataKey="createGuestCart"/> - <requiredEntity createDataKey="createConfigProduct"/> - </createData> - <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddress"> - <requiredEntity createDataKey="createGuestCart"/> - </createData> - <updateData createDataKey="createGuestCart" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformation"> - <requiredEntity createDataKey="createGuestCart"/> - </updateData> + <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="saveChanges"/> - <!-- <amOnPage url="$$createConfigProduct.sku$$.html" stepKey="navigateToProductPage"/> + <amOnPage url="$$createConfigProduct.sku$$.html" stepKey="navigateToProductPage"/> <waitForPageLoad stepKey="waitForProductPage"/> <fillField selector="{{StorefrontProductInfoMainSection.qty}}" userInput="4" stepKey="fillQuantity"/> @@ -79,10 +63,10 @@ <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> </actionGroup> - <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> --> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> <actionGroup ref="FilterOrderGridByIdActionGroup" stepKey="filterOrderGridById"> - <argument name="orderId" value="$createGuestCart.return$"/> + <argument name="orderId" value="$grabOrderNumber"/> </actionGroup> <actionGroup ref="AdminOrderGridClickFirstRowActionGroup" stepKey="clickOrderRow"/> @@ -91,16 +75,11 @@ <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQuantity"/> <waitForPageLoad stepKey="waitPageToBeLoaded"/> <actionGroup ref="AdminInvoiceClickSubmitActionGroup" stepKey="clickSubmitInvoice"/> - <!-- <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction"/> - <waitForPageLoad stepKey="waitOrderDetailToLoad"/> --> - <!-- <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="1" stepKey="changeItemQtyToShip"/> --> - <actionGroup ref="AdminCreateShipmentFromOrderPage" stepKey="clickSubmitShipment"> - <argument name="Qty" value="1"/> - <argument name="Number" value="111"/> - </actionGroup> - - <!-- <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment"/> - <waitForPageLoad stepKey="waitShipmentSectionToLoad"/> --> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction"/> + <waitForPageLoad stepKey="waitOrderDetailToLoad"/> + <fillField selector="{{AdminShipmentItemsSection.itemQtyToShip('1')}}" userInput="1" stepKey="changeItemQtyToShip"/> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment"/> + <waitForPageLoad stepKey="waitShipmentSectionToLoad"/> <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOption"> <argument name="orderStatus" value="Complete"/> </actionGroup> diff --git a/app/code/Magento/Quote/Test/Mftf/Data/CartItemData.xml b/app/code/Magento/Quote/Test/Mftf/Data/CartItemData.xml index a513b6747f612..d24154bcf9da2 100644 --- a/app/code/Magento/Quote/Test/Mftf/Data/CartItemData.xml +++ b/app/code/Magento/Quote/Test/Mftf/Data/CartItemData.xml @@ -23,4 +23,9 @@ <var key="quote_id" entityKey="return" entityType="GuestCart"/> <var key="sku" entityKey="sku" entityType="product"/> </entity> + <entity name="FourCartItems" type="CartItem"> + <data key="qty">4</data> + <var key="quote_id" entityKey="return" entityType="GuestCart"/> + <var key="sku" entityKey="sku" entityType="product"/> + </entity> </entities> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml index 092a225c232ea..334061803bb4d 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml @@ -10,7 +10,10 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminInvoiceWIthUpdatedProductQtyActionGroup" extends="AdminCreateInvoiceActionGroup"> <annotations> - <description>The "Create Invoice" page: Update product qty to invoice (there is one product in the Order).</description> + <description>Start order Invoicing. + Update product qty to invoice (there is one product in the Order). + Submit the invoice. + </description> </annotations> <arguments> <argument name="qty" type="string"/> From 9bffc0892aeb17a2b7091caff07b278f987f3811 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 16:52:33 +0200 Subject: [PATCH 137/346] refactored --- .../Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml index 5270c82a7e977..899ed7f1e60ba 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml @@ -19,6 +19,9 @@ <testCaseId value="MAGETWO-97228"/> <useCaseId value="MAGETWO-82221"/> <group value="ConfigurableProduct"/> + <skip> + <issueId value="DEPRECATED">Use AdminCheckProductQtyAfterOrderCancellingTest instead</issueId> + </skip> </annotations> <before> From ad511d6c8f8c5ed8ee3458346bdef6bb378f054a Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 16:56:40 +0200 Subject: [PATCH 138/346] refactored stepKeys --- .../AdminCheckProductQtyAfterOrderCancelling.xml | 14 +++++++------- ...dminInvoiceWIthUpdatedProductQtyActionGroup.xml | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml index 71eddf6667368..551269945bd81 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml @@ -54,22 +54,22 @@ <argument name="orderId" value="$createGuestCart.return$"/> </actionGroup> - <actionGroup ref="AdminOrderGridClickFirstRowActionGroup" stepKey="clickOrderRow"/> + <actionGroup ref="AdminOrderGridClickFirstRowActionGroup" stepKey="openOrder"/> - <actionGroup ref="AdminInvoiceWIthUpdatedProductQtyActionGroup" stepKey="ChangeQtyToInvoice"> + <actionGroup ref="AdminInvoiceWIthUpdatedProductQtyActionGroup" stepKey="createPartialInvoice"> <argument name="qty" value="1"/> </actionGroup> - <actionGroup ref="AdminCreateShipmentFromOrderPage" stepKey="clickSubmitShipment"> + <actionGroup ref="AdminCreateShipmentFromOrderPage" stepKey="createShipment"> <argument name="Qty" value="1"/> <argument name="Number" value="111"/> </actionGroup> - <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelPendingOption"> + <actionGroup ref="CancelPendingOrderActionGroup" stepKey="cancelOrder"> <argument name="orderStatus" value="Complete"/> </actionGroup> - <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Canceled 3" stepKey="seeCanceledQuantity"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Canceled 3" stepKey="seeCanceledQty"/> <actionGroup ref="AdminOpenCatalogProductPageActionGroup" stepKey="goToCatalogProductPage"/> @@ -77,13 +77,13 @@ <argument name="sku" value="$$createConfigProduct.sku$$"/> </actionGroup> - <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="seeProductSkuInGrid"> + <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="assertProductDataInGrid"> <argument name="row" value="1"/> <argument name="column" value="Quantity"/> <argument name="value" value="99"/> </actionGroup> - <actionGroup ref="AdminClearFiltersActionGroup" stepKey="clearProductFilters"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="clearFilters"/> </test> </tests> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml index 334061803bb4d..cc02bdc66c18b 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml @@ -19,8 +19,8 @@ <argument name="qty" type="string"/> </arguments> - <fillField selector="{{AdminInvoiceItemsSection.qtyToInvoiceColumn}}" userInput="{{qty}}" stepKey="changeQtyToInvoice" after="waitForInvoicePage"/> - <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQuantity" after="changeQtyToInvoice"/> - <waitForPageLoad stepKey="waitPageToBeLoaded" after="updateQuantity"/> + <fillField selector="{{AdminInvoiceItemsSection.qtyToInvoiceColumn}}" userInput="{{qty}}" stepKey="fillQtyField" after="waitForInvoicePage"/> + <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="clickUpdateQuantityButton" after="changeQtyToInvoice"/> + <waitForPageLoad stepKey="waitForPageRefreshed" after="updateQuantity"/> </actionGroup> </actionGroups> From f1b6aed98ee775ae6c6d672c6befbe563483fd2e Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Mon, 30 Nov 2020 17:04:22 +0200 Subject: [PATCH 139/346] MC-39072: JS error is shown on the checkout --- .../view/frontend/web/template/billing-address/details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html index 23bbce48fee2c..e4000e2d120f9 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html @@ -7,7 +7,7 @@ <div if="isAddressDetailsVisible() && currentBillingAddress()" class="billing-address-details"> <text args="currentBillingAddress().prefix"/> <text args="currentBillingAddress().firstname"/> <text args="currentBillingAddress().middlename"/> <text args="currentBillingAddress().lastname"/> <text args="currentBillingAddress().suffix"/><br/> - <text args="_.values(currentBillingAddress().street).join(', ')"/><br/> + <text args="currentBillingAddress().street"/><br/> <text args="currentBillingAddress().city "/>, <span text="currentBillingAddress().region"></span> <text args="currentBillingAddress().postcode"/><br/> <text args="getCountryName(currentBillingAddress().countryId)"/><br/> <a if="currentBillingAddress().telephone" attr="'href': 'tel:' + currentBillingAddress().telephone" text="currentBillingAddress().telephone"></a><br/> From 7320189463af8d2a08f6138e524ed4838195d179 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 17:15:08 +0200 Subject: [PATCH 140/346] refactored --- .../Mftf/Test/AddOutOfStockProductToCompareListTest.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml index c28c5a040e553..d8545c94010dc 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml @@ -87,13 +87,12 @@ <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForStorefrontProductComparePageLoad"/> <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInCompareList"> - <argument name="productVar" value="$$product$$"/> + <argument name="productVar" value="$$product$$"/> </actionGroup> - - <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="deleteProdFromCmpList"/> - <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="onCategoryPage"/> - <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="waitForPageLoad1"> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="deleteProdFromCmpList"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="onCategoryPage"/> + <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="waitForPageLoad1"> <argument name="categoryName" value="$$category.name$$"/> </actionGroup> From 08db336c483bf16fded653e0d42d1aa164db91db Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Mon, 30 Nov 2020 09:26:20 -0600 Subject: [PATCH 141/346] MC-38787: Admin Product Grid Page indicator issue --- ...roup.xml => AdminSearchGridByStringNoClearActionGroup.xml} | 4 ++-- .../Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename app/code/Magento/Catalog/Test/Mftf/ActionGroup/{SearchProductGridByStringNoClearActionGroup.xml => AdminSearchGridByStringNoClearActionGroup.xml} (82%) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSearchGridByStringNoClearActionGroup.xml similarity index 82% rename from app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml rename to app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSearchGridByStringNoClearActionGroup.xml index 95ddfd37c0037..afaa3c28c56e8 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/SearchProductGridByStringNoClearActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSearchGridByStringNoClearActionGroup.xml @@ -8,9 +8,9 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="SearchProductGridByStringNoClearActionGroup"> + <actionGroup name="AdminSearchGridByStringNoClearActionGroup"> <annotations> - <description>Searches the Admin Products grid by string without clearing filters.</description> + <description>Search the Admin grid by string without clearing filters.</description> </annotations> <arguments> <argument name="keyword" defaultValue="" type="string"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml index f833171166141..9bb7064b1870b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminGridPageNumberSetsToOneAfterNewSearchTest.xml @@ -80,7 +80,7 @@ </actionGroup> <!-- Performing the first search and assertions --> - <actionGroup ref="SearchProductGridByStringNoClearActionGroup" stepKey="searchForSimpleProduct"> + <actionGroup ref="AdminSearchGridByStringNoClearActionGroup" stepKey="searchForSimpleProduct"> <argument name="keyword" value="SimpleProduct"/> </actionGroup> <actionGroup ref="AdminGridAssertTotalPageCountActionGroup" stepKey="waitForTotalPagesCountFourToBeVisible"> @@ -92,7 +92,7 @@ </actionGroup> <!-- Performing the second search and assertions of successful current page number reset --> - <actionGroup ref="SearchProductGridByStringNoClearActionGroup" stepKey="searchForVirtualProduct"> + <actionGroup ref="AdminSearchGridByStringNoClearActionGroup" stepKey="searchForVirtualProduct"> <argument name="keyword" value="VirtualProduct"/> </actionGroup> <actionGroup ref="AdminGridAssertTotalPageCountActionGroup" stepKey="waitForTotalPagesCountThreeToBeVisible"> From 234c78407a5f3ab56b6b060824456d872188bd41 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 19:52:32 +0200 Subject: [PATCH 142/346] refactoring --- .../Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml | 2 +- .../AdminInvoiceWIthUpdatedProductQtyActionGroup.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml index 551269945bd81..0b9b5c98d9884 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml @@ -56,7 +56,7 @@ <actionGroup ref="AdminOrderGridClickFirstRowActionGroup" stepKey="openOrder"/> - <actionGroup ref="AdminInvoiceWIthUpdatedProductQtyActionGroup" stepKey="createPartialInvoice"> + <actionGroup ref="AdminInvoiceWithUpdatedProductQtyActionGroup" stepKey="createPartialInvoice"> <argument name="qty" value="1"/> </actionGroup> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml index cc02bdc66c18b..c9c9d5bf1e573 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml @@ -8,7 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminInvoiceWIthUpdatedProductQtyActionGroup" extends="AdminCreateInvoiceActionGroup"> + <actionGroup name="AdminInvoiceWithUpdatedProductQtyActionGroup" extends="AdminCreateInvoiceActionGroup"> <annotations> <description>Start order Invoicing. Update product qty to invoice (there is one product in the Order). From 56e2026e62d1d73cf91c2382bc95bee5971c1063 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 19:54:52 +0200 Subject: [PATCH 143/346] add "DEPRECATED" to title --- .../Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml index 899ed7f1e60ba..4baceead08a07 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/ProductsQtyReturnAfterOrderCancelTest.xml @@ -13,7 +13,7 @@ <annotations> <features value="ConfigurableProduct"/> <stories value="Cancel order"/> - <title value="Product quantity return after order cancel"/> + <title value="DEPRECATED. Product quantity return after order cancel"/> <description value="Check Product quantity return after order cancel"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-97228"/> From 0d93b240eeecfb16c71c35d9090160d4f0774d13 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Mon, 30 Nov 2020 19:59:56 +0200 Subject: [PATCH 144/346] refactored --- .../AdminInvoiceWIthUpdatedProductQtyActionGroup.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml index c9c9d5bf1e573..0f602c42ade25 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml @@ -20,7 +20,7 @@ </arguments> <fillField selector="{{AdminInvoiceItemsSection.qtyToInvoiceColumn}}" userInput="{{qty}}" stepKey="fillQtyField" after="waitForInvoicePage"/> - <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="clickUpdateQuantityButton" after="changeQtyToInvoice"/> - <waitForPageLoad stepKey="waitForPageRefreshed" after="updateQuantity"/> + <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="clickUpdateQuantityButton" after="fillQtyField"/> + <waitForPageLoad stepKey="waitForPageRefreshed" after="clickUpdateQuantityButton"/> </actionGroup> </actionGroups> From 04bd4bda3043fd2d347da36d37f1a8234530f48b Mon Sep 17 00:00:00 2001 From: Anna Pak <58164147+AnnaAPak@users.noreply.github.com> Date: Mon, 30 Nov 2020 20:05:32 +0200 Subject: [PATCH 145/346] Rename AdminInvoiceWIthUpdatedProductQtyActionGroup.xml to AdminInvoiceWithUpdatedProductQtyActionGroup.xml --- ...Group.xml => AdminInvoiceWithUpdatedProductQtyActionGroup.xml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/code/Magento/Sales/Test/Mftf/ActionGroup/{AdminInvoiceWIthUpdatedProductQtyActionGroup.xml => AdminInvoiceWithUpdatedProductQtyActionGroup.xml} (100%) diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWithUpdatedProductQtyActionGroup.xml similarity index 100% rename from app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWIthUpdatedProductQtyActionGroup.xml rename to app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceWithUpdatedProductQtyActionGroup.xml From 3e88e175e7ae6609bc8e54a669b988c86ba310ad Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Mon, 30 Nov 2020 13:28:56 -0600 Subject: [PATCH 146/346] MC-38770: Exception during initialization is cacheable - moved dependency to use --- lib/internal/Magento/Framework/App/Bootstrap.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/App/Bootstrap.php b/lib/internal/Magento/Framework/App/Bootstrap.php index 92b925836b295..83f292cfdf703 100644 --- a/lib/internal/Magento/Framework/App/Bootstrap.php +++ b/lib/internal/Magento/Framework/App/Bootstrap.php @@ -13,6 +13,7 @@ use Magento\Framework\Autoload\Populator; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Filesystem\DriverPool; +use Magento\Framework\HTTP\PhpEnvironment\Response; use Psr\Log\LoggerInterface; /** @@ -428,8 +429,8 @@ public function isDeveloperMode() */ protected function terminate(\Throwable $e) { - /** @var \Magento\Framework\HTTP\PhpEnvironment\Response $response */ - $response = $this->objectManager->get(\Magento\Framework\HTTP\PhpEnvironment\Response::class); + /** @var Response $response */ + $response = $this->objectManager->get(Response::class); $response->clearHeaders(); $response->setHttpResponseCode(500); $response->setHeader('Content-Type', 'text/plain'); From b9b60277c3d967bd8d570e9491d92e3fe4800992 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Mon, 30 Nov 2020 13:49:31 -0600 Subject: [PATCH 147/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../AdminOpenCMSBlocksGridActionGroup.xml | 19 ------------------- .../AdminOpenCmsBlocksGridActionGroup.xml | 18 ------------------ 2 files changed, 37 deletions(-) delete mode 100644 app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCMSBlocksGridActionGroup.xml delete mode 100644 app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCMSBlocksGridActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCMSBlocksGridActionGroup.xml deleted file mode 100644 index 18e7e5fb52615..0000000000000 --- a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCMSBlocksGridActionGroup.xml +++ /dev/null @@ -1,19 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminOpenCMSBlocksGridActionGroup"> - <annotations> - <description>Navigate to the Admin Blocks Grid page.</description> - </annotations> - - <amOnPage url="{{CmsBlocksPage.url}}" stepKey="navigateToCMSBlocksGrid"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - </actionGroup> -</actionGroups> diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml deleted file mode 100644 index 4b57e0c1274f6..0000000000000 --- a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminOpenCmsBlocksGridActionGroup"> - <annotations> - <description>Goes to the Cms Blocks grid page.</description> - </annotations> - <amOnPage url="{{CmsBlocksPage.url}}" stepKey="navigateToCMSBlocksGrid"/> - <waitForPageLoad stepKey="waitForPageLoad"/> - </actionGroup> -</actionGroups> From 12fcd207b8527d60260e788cd2d62769492d8567 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Mon, 30 Nov 2020 13:51:19 -0600 Subject: [PATCH 148/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml index 1e3cf57e8777b..4813d8aefdb8d 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml @@ -10,6 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="SalesRuleConsumerData"> <data key="consumerName">sales.rule.update.coupon.usage</data> - <data key="messageLimit">100</data> + <data key="messageLimit">3</data> </entity> </entities> From 4e82e08520c277bf07fd9436d467dbc8c9511ff7 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Mon, 30 Nov 2020 13:53:57 -0600 Subject: [PATCH 149/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index f33cf60b4ef6a..da9acc71b33b1 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -63,7 +63,7 @@ <argument name="consumerName" value="{{AdminCodeGeneratorMessageConsumerData.consumerName}}"/> <argument name="maxMessages" value="{{AdminCodeGeneratorMessageConsumerData.messageLimit}}"/> </actionGroup> - <actionGroup ref="CliConsumerStartActionGroup" stepKey="startSalesRuleMessageQueue"> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue"> <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> </actionGroup> From a53949837ce15882e638a297a43ff7415db76801 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Mon, 30 Nov 2020 14:03:05 -0600 Subject: [PATCH 150/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../AdminOpenCmsBlocksGridActionGroup.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml new file mode 100644 index 0000000000000..4b57e0c1274f6 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminOpenCmsBlocksGridActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminOpenCmsBlocksGridActionGroup"> + <annotations> + <description>Goes to the Cms Blocks grid page.</description> + </annotations> + <amOnPage url="{{CmsBlocksPage.url}}" stepKey="navigateToCMSBlocksGrid"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> +</actionGroups> From 2ed8a461e23641f6fea9fa566b9fe69de1a01f34 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Mon, 30 Nov 2020 15:29:47 -0600 Subject: [PATCH 151/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Test/StorefrontAutoGeneratedCouponCodeTest.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index da9acc71b33b1..1c63796827785 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -63,10 +63,6 @@ <argument name="consumerName" value="{{AdminCodeGeneratorMessageConsumerData.consumerName}}"/> <argument name="maxMessages" value="{{AdminCodeGeneratorMessageConsumerData.messageLimit}}"/> </actionGroup> - <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue"> - <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> - <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> - </actionGroup> <actionGroup ref="ReloadPageActionGroup" stepKey="refreshPage"/> <comment userInput="Replacing reload action and preserve Backward Compatibility" stepKey="waitFormToReload1"/> <conditionalClick selector="{{AdminCartPriceRulesFormSection.manageCouponCodesHeader}}" @@ -105,10 +101,16 @@ <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyPayment"/> <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> <waitForElement selector="{{CheckoutSuccessMainSection.success}}" time="30" stepKey="waitForLoadSuccessPage"/> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue"> + <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> + <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> + </actionGroup> + <reloadPage stepKey="refreshPage1"/> <!-- Step: 9-10. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage1"/> <waitForPageLoad stepKey="waitForPageLoad3"/> + <reloadPage stepKey="refreshPage2"/> <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule1"> <argument name="product" value="$$createSimpleProduct$$"/> <argument name="couponCode" value="{$couponCode}"/> From 8ba2695458f6c686a1caafb5cd629b0f67a85f10 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 1 Dec 2020 08:57:26 +0200 Subject: [PATCH 152/346] fixed indentation --- .../StorefrontHoverProductOnCategoryPageActionGroup.xml | 4 ++-- .../Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml index 661d40fd4f13a..10d85a91a02c6 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontHoverProductOnCategoryPageActionGroup.xml @@ -10,10 +10,10 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="StorefrontHoverProductOnCategoryPageActionGroup"> <annotations> - <description>Hover product on the Category page</description> + <description>Hover product on the Category page</description> </annotations> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverOverProduct"/> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverOverProduct"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml index d8545c94010dc..8911e5d04fe4a 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml @@ -31,7 +31,7 @@ </before> <after> - <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockDisable.path}} {{CatalogInventoryOptionsShowOutOfStockDisable.value}}" stepKey="setConfigShowOutOfStockFalse"/> + <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockDisable.path}} {{CatalogInventoryOptionsShowOutOfStockDisable.value}}" stepKey="setConfigShowOutOfStockFalse"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> From d001c99173bbf407587b4ece8f8d51fec6e4f56c Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 1 Dec 2020 09:00:50 +0200 Subject: [PATCH 153/346] fixed indentation --- .../Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml index 8911e5d04fe4a..7f4228a21f3d5 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml @@ -120,7 +120,7 @@ <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForStorefrontProductComparePageLoad2"/> <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInCompareList2"> - <argument name="productVar" value="$$product$$"/> + <argument name="productVar" value="$$product$$"/> </actionGroup> </test> From ffc0ab716c986735427125dd594449e8aac05f41 Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Tue, 1 Dec 2020 10:17:20 +0200 Subject: [PATCH 154/346] update severity, testCaseId --- .../AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml index 4436aab59874a..38b85828c3421 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminOpenCreditmemoViewPageWithWrongCreditmemoIdTest.xml @@ -13,7 +13,8 @@ <stories value="Creditmemo Page With Wrong Creditmemo Id"/> <title value="Open Creditmemo View Page with Wrong Creditmemo Id"/> <description value="Open Creditmemo View Page with Wrong Creditmemo Id."/> - <severity value="MAJOR"/> + <severity value="BLOCKER"/> + <testCaseId value="MC-39500"/> <group value="sales"/> </annotations> <before> From 247817a04340e82b5246761888acfca82eee7736 Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Tue, 1 Dec 2020 10:18:35 +0200 Subject: [PATCH 155/346] update severity, testCaseId --- .../Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml index ce8d6414e2882..d60dca08e6813 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Test/AdminOpenShipmentViewPageWithWrongShipmentIdTest.xml @@ -13,7 +13,8 @@ <stories value="Shipment Page With Wrong Shipment Id"/> <title value="Open Shipment View Page with Wrong Shipment Id"/> <description value="Open Shipment View Page with Wrong Shipment Id."/> - <severity value="MAJOR"/> + <severity value="BLOCKER"/> + <testCaseId value="MC-39502"/> <group value="shipping"/> </annotations> <before> From 14b9169b13e1a033a2d185ff2c47ceeefc8bef48 Mon Sep 17 00:00:00 2001 From: Stanislav Ilnytskyi <stailx1@gmail.com> Date: Tue, 1 Dec 2020 10:06:51 +0100 Subject: [PATCH 156/346] fix unit test --- .../Test/Unit/Model/Indexer/ProductPriceIndexFilterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/ProductPriceIndexFilterTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/ProductPriceIndexFilterTest.php index 0f3d8be212e30..090a74afca050 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/ProductPriceIndexFilterTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/ProductPriceIndexFilterTest.php @@ -82,7 +82,7 @@ public function testModifyPrice() $connectionMock->expects($this->once())->method('select')->willReturn($selectMock); $selectMock->expects($this->at(2)) ->method('where') - ->with('stock_item.product_id in (?)', $entityIds) + ->with('stock_item.product_id IN (?)', $entityIds) ->willReturn($selectMock); $this->generator->expects($this->once()) ->method('generate') From 9847f03d47e5027c7f27c4e5c800896a5b199582 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 1 Dec 2020 11:47:05 +0200 Subject: [PATCH 157/346] init --- .../Sales/Test/Mftf/Metadata/InvoiceMeta.xml | 14 +++++ .../Test/Mftf/Test/AdminCreateInvoice.xml | 53 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml new file mode 100644 index 0000000000000..30355882b20df --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateInvoice" dataType="Invoice" type="create" auth="adminOauth" url="V1/order/29/invoices" method="POST"> + <contentType>application/json</contentType> + </operation> +</operations> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml new file mode 100644 index 0000000000000..74912e1037436 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCreateInvoice"> + <annotations> + <features value="Sales"/> + <stories value="1Create an Invoice via the Admin"/> + <title value="1111Admin should be able to create an invoice"/> + <description value="1Admin should be able to create an invoice"/> + <severity value="MAJOR"/> + <testCaseId value="1MAGETWO-72096"/> + <group value="sales"/> + </annotations> + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + + <createData entity="defaultSimpleProduct" stepKey="createConfigProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + + <createData entity="GuestCart" stepKey="createGuestCart"/> + <createData entity="SimpleCartItem" stepKey="addCartItem"> + <requiredEntity createDataKey="createGuestCart"/> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddress"> + <requiredEntity createDataKey="createGuestCart"/> + </createData> + <updateData createDataKey="createGuestCart" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformation"> + <requiredEntity createDataKey="createGuestCart"/> + </updateData> + + <createData entity="Invoice" stepKey="invoiceOrder"/> + + + </before> + <after> + <!-- <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> --> + <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> + </after> + + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + + </test> +</tests> From e3ff240f0b1991a2ca8f9cdaa31ee4e9cda95211 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Tue, 1 Dec 2020 11:48:49 +0200 Subject: [PATCH 158/346] MC-36383: [B2B] A Product with Customizable Option (File) can not be added from a Requisition List to the Shopping Cart --- .../_files/customer_quote_with_items_simple_product_options.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/customer_quote_with_items_simple_product_options.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/customer_quote_with_items_simple_product_options.php index f0ba56f7179aa..4c003c209e3c2 100644 --- a/dev/tests/integration/testsuite/Magento/Checkout/_files/customer_quote_with_items_simple_product_options.php +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/customer_quote_with_items_simple_product_options.php @@ -67,7 +67,7 @@ $iDate++; break; case ProductCustomOptionInterface::OPTION_GROUP_FILE: - $value = 'test.jpg'; + $value = null; break; default: $value = 'test'; From 901daf6771ca2179c886f25c80604f4105da0f83 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Tue, 1 Dec 2020 12:10:02 +0200 Subject: [PATCH 159/346] remove preventDefault() --- .../Framework/View/Helper/SecureHtmlRenderer.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php index d926e85ae4f8f..052c51441d451 100644 --- a/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php +++ b/lib/internal/Magento/Framework/View/Helper/SecureHtmlRenderer.php @@ -8,7 +8,6 @@ namespace Magento\Framework\View\Helper; -use Magento\Framework\Api\SimpleDataObjectConverter; use Magento\Framework\Math\Random; use Magento\Framework\View\Helper\SecureHtmlRender\EventHandlerData; use Magento\Framework\View\Helper\SecureHtmlRender\HtmlRenderer; @@ -105,27 +104,26 @@ public function renderEventListenerAsTag( } $random = $this->random->getRandomString(10); - $listenerFunction = 'eventListener' .$random; - $elementName = 'listenedElement' .$random; + $listenerFunction = 'eventListener' . $random; + $elementName = 'listenedElement' . $random; $script = <<<script function {$listenerFunction} () { {$attributeJavascript}; } var {$elementName}Array = document.querySelectorAll("{$elementSelector}"); if({$elementName}Array.length !== 'undefined'){ - {$elementName}Array.forEach(function(element){ + {$elementName}Array.forEach(function(element) { if (element) { element.{$eventName} = function (event) { - event.preventDefault(); var targetElement = element; if (event && event.target) { targetElement = event.target; } {$listenerFunction}.apply(targetElement); - } + }; } }); - } + } script; return $this->renderTag('script', ['type' => 'text/javascript'], $script, false); @@ -145,7 +143,7 @@ public function renderStyleAsTag(string $style, string $selector): string throw new \InvalidArgumentException('Invalid style data given'); } - $elementVariable = 'elem' .$this->random->getRandomString(8); + $elementVariable = 'elem' . $this->random->getRandomString(8); /** @var string[] $styles */ $stylesAssignments = ''; foreach ($stylePairs as $stylePair) { @@ -167,7 +165,7 @@ public function renderStyleAsTag(string $style, string $selector): string 'script', ['type' => 'text/javascript'], "var $elementVariable = document.querySelector('$selector');\n" - ."if ($elementVariable) {\n{$stylesAssignments}}", + . "if ($elementVariable) {\n{$stylesAssignments}}", false ); } From e34fc7826d04dcd7e504082d5fa0d7f029343225 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 1 Dec 2020 13:10:44 +0200 Subject: [PATCH 160/346] ready --- app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml | 7 ++++++- .../Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml index 30355882b20df..250d657c123ff 100644 --- a/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml @@ -8,7 +8,12 @@ <operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> - <operation name="CreateInvoice" dataType="Invoice" type="create" auth="adminOauth" url="V1/order/29/invoices" method="POST"> + <operation name="CreateInvoice" dataType="Invoice" type="create" auth="adminOauth" url="V1/order/{return}/invoice" method="POST"> <contentType>application/json</contentType> + <object key="cartItem" dataType="CartItem"> + <field key="quote_id">string</field> + <field key="sku" type="string">string</field> + <field key="qty">integer</field> + </object> </operation> </operations> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml index 74912e1037436..b75be4652c483 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml @@ -37,8 +37,9 @@ <requiredEntity createDataKey="createGuestCart"/> </updateData> - <createData entity="Invoice" stepKey="invoiceOrder"/> - + <createData entity="Invoice" stepKey="invoiceOrder"> + <requiredEntity createDataKey="createGuestCart"/> + </createData> </before> <after> From beb0fda08417c7dfec5063a1335639cb356cd9f2 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 1 Dec 2020 13:19:17 +0200 Subject: [PATCH 161/346] refactored --- app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml | 2 -- app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml index 250d657c123ff..e0bbfa1cd6e5f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/InvoiceMeta.xml @@ -12,8 +12,6 @@ <contentType>application/json</contentType> <object key="cartItem" dataType="CartItem"> <field key="quote_id">string</field> - <field key="sku" type="string">string</field> - <field key="qty">integer</field> </object> </operation> </operations> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml index b75be4652c483..51aaa251fa3d9 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml @@ -43,8 +43,8 @@ </before> <after> - <!-- <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> --> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> </after> From 320748f555d4036d50ed83ebb32a81972aa29579 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 1 Dec 2020 13:45:26 +0200 Subject: [PATCH 162/346] added Shipment, CreditMemo --- .../Sales/Test/Mftf/Data/CreditMemoData.xml | 17 +++++++++++++++++ .../Sales/Test/Mftf/Data/InvoiceData.xml | 17 +++++++++++++++++ .../Sales/Test/Mftf/Data/ShipmentData.xml | 17 +++++++++++++++++ .../Sales/Test/Mftf/Metadata/CreditMemoMeta.xml | 17 +++++++++++++++++ .../Sales/Test/Mftf/Metadata/ShipmentMeta.xml | 17 +++++++++++++++++ .../Sales/Test/Mftf/Test/AdminCreateInvoice.xml | 10 +++++++++- 6 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Data/CreditMemoData.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Data/InvoiceData.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Data/ShipmentData.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Metadata/ShipmentMeta.xml diff --git a/app/code/Magento/Sales/Test/Mftf/Data/CreditMemoData.xml b/app/code/Magento/Sales/Test/Mftf/Data/CreditMemoData.xml new file mode 100644 index 0000000000000..dc6280f7b3444 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Data/CreditMemoData.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + + <entity name="CreditMemo" type="CreditMemo"> + <var key="quote_id" entityKey="return" entityType="CustomerCart"/> + </entity> + +</entities> diff --git a/app/code/Magento/Sales/Test/Mftf/Data/InvoiceData.xml b/app/code/Magento/Sales/Test/Mftf/Data/InvoiceData.xml new file mode 100644 index 0000000000000..b55ef96932100 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Data/InvoiceData.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + + <entity name="Invoice" type="Invoice"> + <var key="quote_id" entityKey="return" entityType="CustomerCart"/> + </entity> + +</entities> diff --git a/app/code/Magento/Sales/Test/Mftf/Data/ShipmentData.xml b/app/code/Magento/Sales/Test/Mftf/Data/ShipmentData.xml new file mode 100644 index 0000000000000..96d371d3aaf3a --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Data/ShipmentData.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + + <entity name="Shipment" type="Shipment"> + <var key="quote_id" entityKey="return" entityType="CustomerCart"/> + </entity> + +</entities> diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml new file mode 100644 index 0000000000000..3b500d61b1c35 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateCreditMemo" dataType="CreditMemo" type="create" auth="adminOauth" url="V1/order/{return}/refund" method="POST"> + <contentType>application/json</contentType> + <object key="cartItem" dataType="CartItem"> + <field key="quote_id">string</field> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/ShipmentMeta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/ShipmentMeta.xml new file mode 100644 index 0000000000000..1c9de02c6a2e7 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/ShipmentMeta.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateShipment" dataType="Shipment" type="create" auth="adminOauth" url="V1/order/{return}/ship" method="POST"> + <contentType>application/json</contentType> + <object key="cartItem" dataType="CartItem"> + <field key="quote_id">string</field> + </object> + </operation> +</operations> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml index 51aaa251fa3d9..3dc1c3ed98d03 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml @@ -35,10 +35,18 @@ </createData> <updateData createDataKey="createGuestCart" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformation"> <requiredEntity createDataKey="createGuestCart"/> - </updateData> + </updateData> <createData entity="Invoice" stepKey="invoiceOrder"> <requiredEntity createDataKey="createGuestCart"/> + </createData> + + <createData entity="Shipment" stepKey="shipOrder"> + <requiredEntity createDataKey="createGuestCart"/> + </createData> + + <createData entity="CreditMemo" stepKey="refundMemo"> + <requiredEntity createDataKey="createGuestCart"/> </createData> </before> From 53b85cce1e95a5cfb60db6dc029e551d053e1f14 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Tue, 1 Dec 2020 14:00:14 +0200 Subject: [PATCH 163/346] MC-39072: JS error is shown on the checkout --- .../view/frontend/web/template/billing-address/details.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html index e4000e2d120f9..6b3de69d1a21d 100644 --- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html +++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html @@ -7,7 +7,7 @@ <div if="isAddressDetailsVisible() && currentBillingAddress()" class="billing-address-details"> <text args="currentBillingAddress().prefix"/> <text args="currentBillingAddress().firstname"/> <text args="currentBillingAddress().middlename"/> <text args="currentBillingAddress().lastname"/> <text args="currentBillingAddress().suffix"/><br/> - <text args="currentBillingAddress().street"/><br/> + <text args="currentBillingAddress().street.join(', ')"/><br/> <text args="currentBillingAddress().city "/>, <span text="currentBillingAddress().region"></span> <text args="currentBillingAddress().postcode"/><br/> <text args="getCountryName(currentBillingAddress().countryId)"/><br/> <a if="currentBillingAddress().telephone" attr="'href': 'tel:' + currentBillingAddress().telephone" text="currentBillingAddress().telephone"></a><br/> From d2ab2f389d64d349dca0ddc3246654c94c806cc3 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 1 Dec 2020 14:25:38 +0200 Subject: [PATCH 164/346] AdminCancelTheOrderWithCashOnDeliveryPaymentMethodTest refactoring (in progress) --- .../Quote/Test/Mftf/Data/CustomerCartData.xml | 7 + ...ssOrdersCancelCompleteAndClosedAPITest.xml | 134 ++++++++++++++++++ ...nMassOrdersCancelCompleteAndClosedTest.xml | 7 +- 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml diff --git a/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml b/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml index a14be3b533fa8..affebbc07ad61 100755 --- a/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml +++ b/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml @@ -24,4 +24,11 @@ <requiredEntity type="payment_method">PaymentMethodCheckMoneyOrder</requiredEntity> <requiredEntity type="billing_address">BillingAddressTX</requiredEntity> </entity> + + <entity name="CustomerOrderPaymentMethod" type="CustomerPaymentInformation"> + <var key="cart_id" entityKey="return" entityType="CustomerCart"/> + <requiredEntity type="payment_method">PaymentMethodCheckMoneyOrder</requiredEntity> + <requiredEntity type="billing_address">BillingAddressTX</requiredEntity> + </entity> + </entities> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml new file mode 100644 index 0000000000000..5ed660b21c6df --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminMassOrdersCancelCompleteAndClosedAPITest"> + <annotations> + <stories value="Mass Update Orders"/> + <title value="Mass cancel orders in status Complete, Closed"/> + <description value="Try to cancel orders in status Complete, Closed"/> + <severity value="MAJOR"/> + <testCaseId value="MC-16183"/> + <group value="sales"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + + <createData entity="ApiCategory" stepKey="createCategory"/> + + <createData entity="defaultSimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + + <createData entity="GuestCart" stepKey="createGuestCartOne"/> + <createData entity="SimpleCartItem" stepKey="addCartItemOne"> + <requiredEntity createDataKey="createGuestCartOne"/> + <requiredEntity createDataKey="createSimpleProduct"/> + </createData> + <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddressOne"> + <requiredEntity createDataKey="createGuestCartOne"/> + </createData> + <updateData createDataKey="createGuestCartOne" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformationOne"> + <requiredEntity createDataKey="createGuestCartOne"/> + </updateData> + + <createData entity="Invoice" stepKey="invoiceOrderOne"> + <requiredEntity createDataKey="createGuestCartOne"/> + </createData> + + <createData entity="Shipment" stepKey="shipOrderOne"> + <requiredEntity createDataKey="createGuestCartOne"/> + </createData> + + + <createData entity="GuestCart" stepKey="createGuestCartTwo"/> + <createData entity="SimpleCartItem" stepKey="addCartItemTwo"> + <requiredEntity createDataKey="createGuestCartTow"/> + <requiredEntity createDataKey="createSimpleProduct"/> + </createData> + <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddressTwo"> + <requiredEntity createDataKey="createGuestCartTwo"/> + </createData> + <updateData createDataKey="createGuestCartTwo" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformationTwo"> + <requiredEntity createDataKey="createGuestCartTwo"/> + </updateData> + + <createData entity="Invoice" stepKey="invoiceOrderTwo"> + <requiredEntity createDataKey="createGuestCartTwo"/> + </createData> + + <createData entity="CreditMemo" stepKey="refundOrderTwo"> + <requiredEntity createDataKey="createGuestCartTwo"/> + </createData> + + </before> + <after> + <!-- Delete data --> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + + <!-- Create first order --> + <!-- <actionGroup ref="CreateOrderActionGroup" stepKey="createFirstOrder"> + <argument name="product" value="$$createProduct$$"/> + <argument name="customer" value="$$createCustomer$$"/> + </actionGroup> + <grabTextFrom selector="|Order # (\d+)|" stepKey="getFirstOrderId"/> + <assertNotEmpty stepKey="assertOrderIdIsNotEmpty" after="getFirstOrderId"> + <actualResult type="const">$getFirstOrderId</actualResult> + </assertNotEmpty> --> + + <!-- Create Shipment for first Order --> + <!-- <actionGroup ref="AdminCreateInvoiceAndShipmentActionGroup" stepKey="createShipmentForFirstOrder"/> --> + + <!-- Create second order --> + <!-- <actionGroup ref="CreateOrderActionGroup" stepKey="createSecondOrder"> + <argument name="product" value="$$createProduct$$"/> + <argument name="customer" value="$$createCustomer$$"/> + </actionGroup> + <grabTextFrom selector="|Order # (\d+)|" stepKey="getSecondOrderId"/> + <assertNotEmpty stepKey="assertSecondOrderIdIsNotEmpty" after="getSecondOrderId"> + <actualResult type="const">$getSecondOrderId</actualResult> + </assertNotEmpty> --> + + <!-- Create CreditMemo for second Order --> + <!-- <actionGroup ref="AdminCreateInvoiceAndCreditMemoActionGroup" stepKey="createCreditMemo"/> --> + + <!-- Navigate to backend: Go to Sales > Orders --> + <actionGroup ref="AdminOrdersPageOpenActionGroup" stepKey="onOrderPage"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFilters"/> + + <!-- Select Mass Action according to dataset: Cancel --> + <actionGroup ref="AdminTwoOrderActionOnGridActionGroup" stepKey="massActionCancel"> + <argument name="action" value="Cancel"/> + <argument name="orderId" value="$createGuestCartOne.return$"/> + <argument name="secondOrderId" value="$createGuestCartTwo.return$"/> + </actionGroup> + <see userInput="You cannot cancel the order(s)." stepKey="assertOrderCancelMassActionFailMessage"/> + + <!--Assert first order in orders grid --> + <actionGroup ref="AdminOrderFilterByOrderIdAndStatusActionGroup" stepKey="seeFirstOrder"> + <argument name="orderId" value="$createGuestCartOne.return$"/> + <argument name="orderStatus" value="Complete"/> + </actionGroup> + <see userInput="$createGuestCartOne.return$" selector="{{AdminOrdersGridSection.gridCell('1','ID')}}" stepKey="assertFirstOrderID"/> + <see userInput="Complete" selector="{{AdminOrdersGridSection.gridCell('1','Status')}}" stepKey="assertFirstOrderStatus"/> + + <!--Assert second order in orders grid --> + <actionGroup ref="AdminOrderFilterByOrderIdAndStatusActionGroup" stepKey="seeSecondOrder"> + <argument name="orderId" value="$createGuestCartTwo.return$"/> + <argument name="orderStatus" value="Closed"/> + </actionGroup> + <see userInput="$createGuestCartTwo.return$" selector="{{AdminOrdersGridSection.gridCell('1','ID')}}" stepKey="assertSecondOrderID"/> + <see userInput="Closed" selector="{{AdminOrdersGridSection.gridCell('1','Status')}}" stepKey="assertSecondStatus"/> + </test> +</tests> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml index b337af3753db3..793e1a07950c9 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml @@ -8,15 +8,18 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AdminMassOrdersCancelCompleteAndClosedTest"> + <test name="AdminMassOrdersCancelCompleteAndClosedTest" deprecated="Use AdminMassOrdersCancelCompleteAndClosedAPITest instead"> <annotations> <stories value="Mass Update Orders"/> - <title value="Mass cancel orders in status Complete, Closed"/> + <title value="DEPRECATED. Mass cancel orders in status Complete, Closed"/> <description value="Try to cancel orders in status Complete, Closed"/> <severity value="MAJOR"/> <testCaseId value="MC-16183"/> <group value="sales"/> <group value="mtf_migrated"/> + <skip> + <issueId value="DEPRECATED">Use AdminMassOrdersCancelCompleteAndClosedAPITest instead</issueId> + </skip> </annotations> <before> <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> From 72574a8e5e6257f52aecb21df4bcd1f3990f31c9 Mon Sep 17 00:00:00 2001 From: "taras.gamanov" <engcom-vendorworker-hotel@adobe.com> Date: Tue, 1 Dec 2020 14:46:37 +0200 Subject: [PATCH 165/346] "MC-14715: Add bundle dynamic product to the cart" has been updated --- .../StorefrontAddBundleDynamicProductToShoppingCartTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddBundleDynamicProductToShoppingCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddBundleDynamicProductToShoppingCartTest.xml index 3c090900563a5..714a06510952f 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddBundleDynamicProductToShoppingCartTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddBundleDynamicProductToShoppingCartTest.xml @@ -94,7 +94,7 @@ <actionGroup ref="ClickViewAndEditCartFromMiniCartActionGroup" stepKey="selectViewAndEditCart"/> <!--Assert Shopping Cart Summary--> - <actionGroup ref="AssertStorefrontShoppingCartSummaryWithShippingActionGroup" stepKey="AssertCartSummary" > + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="AssertCartSummary" > <argument name="subtotal" value="$100.00"/> <argument name="shipping" value="10.00"/> <argument name="total" value="110.00"/> From f5ed249e645a73309438fae73f237dbc1cc3aef8 Mon Sep 17 00:00:00 2001 From: "taras.gamanov" <engcom-vendorworker-hotel@adobe.com> Date: Tue, 1 Dec 2020 14:52:16 +0200 Subject: [PATCH 166/346] "MC-14727: Select one multi select option of a bundle product and add to the shopping cart" has been updated --- ...efrontAddOneBundleMultiSelectOptionToTheShoppingCartTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddOneBundleMultiSelectOptionToTheShoppingCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddOneBundleMultiSelectOptionToTheShoppingCartTest.xml index eff18f9081b67..cd6f4215adb5d 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddOneBundleMultiSelectOptionToTheShoppingCartTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontAddOneBundleMultiSelectOptionToTheShoppingCartTest.xml @@ -88,7 +88,7 @@ <actionGroup ref="ClickViewAndEditCartFromMiniCartActionGroup" stepKey="selectViewAndEditCart"/> <!--Assert Shopping Cart Summary--> - <actionGroup ref="AssertStorefrontShoppingCartSummaryWithShippingActionGroup" stepKey="AssertCartSummary" > + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="AssertCartSummary" > <argument name="subtotal" value="$50.00"/> <argument name="shipping" value="5.00"/> <argument name="total" value="55.00"/> From 328cbaf1e07d902fe806c6d267d1bd1049343126 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Tue, 1 Dec 2020 15:27:44 +0200 Subject: [PATCH 167/346] MC-35717: Admin can not add a Product with a Customizable Option (File) to Order by SKU --- .../Test/Mftf/Section/AdminOrderFormCustomOptionsSection.xml | 2 +- .../Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormCustomOptionsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormCustomOptionsSection.xml index 066aa4181e7ef..49d26d4973874 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormCustomOptionsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormCustomOptionsSection.xml @@ -10,7 +10,7 @@ <section name="AdminOrderFormCustomOptionsSection"> <element name="quantity" type="input" selector="//input[@id='product_composite_configure_input_qty']"/> <element name="file" type="file" selector="//input[@type='file'][contains(@class, 'product-custom-option')]" /> - <element name="buttonOk" type="button" selector="//button[contains(@class, 'action-primary')][@data-role='action']"/> + <element name="buttonOk" type="button" selector="//button[contains(@class, 'action-primary')][@data-role='action']" timeout="30"/> <element name="linkChange" type="text" selector="//div[contains(@class, 'entry-edit')]//a[contains(text(),'Change')]"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml index 4437f6e6775f2..fae0bd4589580 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsOrderedSection.xml @@ -13,7 +13,7 @@ <element name="configureButtonBySku" type="button" selector="//div[@class='sku-configure-button']//span[contains(text(),'Configure')]"/> <element name="configureProductOk" type="button" selector="//div[@class='page-main-actions']//span[contains(text(),'OK')]"/> <element name="configureProductQtyField" type="input" selector="//*[@id='super-product-table']/tbody/tr[{{arg}}]/td[5]/input[1]" parameterized="true"/> - <element name="addProductToOrder" type="input" selector="//*[@title='Add Products to Order']"/> + <element name="addProductToOrder" type="input" selector="//*[@title='Add Products to Order']" timeout="30"/> <element name="itemsOrderedSummaryText" type="textarea" selector="//table[@class='data-table admin__table-primary order-tables']/tfoot/tr"/> <element name="configureSelectAttribute" type="select" selector="select[id*=attribute]"/> <element name="itemsSKU" type="text" selector="(//div[contains(@class, 'product-sku-block')])[{{productNumber}}]" parameterized="true"/> From 71ae5db5ae794f4b79cc991f297b9105a664d664 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Tue, 1 Dec 2020 16:57:41 +0200 Subject: [PATCH 168/346] MC-36779: Product still present in the Wish List after added to order --- .../Magento/Sales/Model/AdminOrder/Create.php | 3 +- .../Adminhtml/Order/Create/LoadBlockTest.php | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 1f23e4480ec1c..d7ddd423733a8 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -970,7 +970,7 @@ public function applySidebarData($data) $item = $this->getCustomerCart()->getItemById($itemId); if ($item) { $this->moveQuoteItem($item, 'order', $qty); - $this->removeItem($itemId, 'cart'); + $data['remove'][$itemId] = 'cart'; } } } @@ -984,6 +984,7 @@ public function applySidebarData($data) ); if ($item->getId()) { $this->addProduct($item->getProduct(), $item->getBuyRequest()->toArray()); + $data['remove'][$itemId] = 'wishlist'; } } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php index b6aa44bac1c4d..104cc74ec1f9b 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php @@ -16,6 +16,7 @@ use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Quote\Model\GetQuoteByReservedOrderId; use Magento\TestFramework\TestCase\AbstractBackendController; +use Magento\Wishlist\Model\Wishlist; /** * Class checks create order load block controller. @@ -201,6 +202,35 @@ public function testMoveFromOrderToShoppingCart(): void $this->quoteIdsToRemove[] = $customerCart->getId(); } + /** + * Check that Wishlist item is deleted after it has been added to Order. + * + * @return void + * @magentoDataFixture Magento/Wishlist/_files/wishlist_with_simple_product.php + */ + public function testAddProductToOrderFromWishList(): void + { + /** @var Wishlist $wishlist */ + $wishlist = $this->_objectManager->create(Wishlist::class); + $wishlistItems = $wishlist->loadByCustomerId(1)->getItemCollection(); + $this->assertCount(1, $wishlistItems); + + $post = $this->hydratePost([ + 'sidebar' => [ + 'add_wishlist_item' => [ + $wishlistItems->getFirstItem()->getId() => 1, + ], + ], + ]); + $params = $this->hydrateParams(); + $this->dispatchWitParams($params, $post); + + $wishlistItems->clear(); + $this->assertEmpty($wishlistItems); + $quoteItems = $this->session->getQuote()->getItemsCollection(); + $this->assertCount(1, $quoteItems); + } + /** * Check customer quotes * From 9eb8dc0ac856f6beb20691e92da92f93063531b0 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Tue, 1 Dec 2020 12:44:40 -0600 Subject: [PATCH 169/346] MC-39279: [ CLARIFICATION ] Product zoom effect on iPhone is not similar to desktop or android zoom effect --- lib/web/magnifier/magnify.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/web/magnifier/magnify.js b/lib/web/magnifier/magnify.js index 559e7782f2476..f0c464f4d9042 100644 --- a/lib/web/magnifier/magnify.js +++ b/lib/web/magnifier/magnify.js @@ -314,7 +314,7 @@ define([ ratio, dimentions = {}; - if (allowZoomIn && (!transitionEnabled || !transitionActive) && (isTouchEnabled || + if (allowZoomIn && (!transitionEnabled && !transitionActive) && (isTouchEnabled || !$(zoomInButtonSelector).hasClass(zoomInDisabled))) { $image = $(fullscreenImageSelector); imgOriginalSize = getImageSize($image[0]); @@ -387,7 +387,7 @@ define([ ratio, fitIntoParent; - if (allowZoomOut && (!transitionEnabled || !transitionActive) && (isTouchEnabled || + if (allowZoomOut && (!transitionEnabled && !transitionActive) && (isTouchEnabled || !$(zoomOutButtonSelector).hasClass(zoomOutDisabled))) { allowZoomIn = true; $image = $(fullscreenImageSelector); @@ -679,7 +679,7 @@ define([ if ($image.hasClass(imageDraggableClass)) { $image.removeClass(imageDraggableClass); } - } else if (gallery.fullScreen && (!transitionEnabled || !transitionActive)) { + } else if (gallery.fullScreen && (!transitionEnabled && !transitionActive)) { imagePosY = getTop($image); imagePosX = $image.offset().left; @@ -719,7 +719,7 @@ define([ var clientX, clientY; - if (gallery.fullScreen && isDragActive && (!transitionEnabled || !transitionActive)) { + if (gallery.fullScreen && isDragActive && (!transitionEnabled && !transitionActive)) { if (allowZoomOut && !$image.hasClass(imageDraggableClass)) { $image.addClass(imageDraggableClass); From 842945116e09540bf4232b1c5e2580b405d2afb3 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Tue, 1 Dec 2020 15:01:48 -0600 Subject: [PATCH 170/346] MC-39279: [ CLARIFICATION ] Product zoom effect on iPhone is not similar to desktop or android zoom effect --- lib/web/magnifier/magnify.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/web/magnifier/magnify.js b/lib/web/magnifier/magnify.js index f0c464f4d9042..7dec3d2d1b9fd 100644 --- a/lib/web/magnifier/magnify.js +++ b/lib/web/magnifier/magnify.js @@ -35,14 +35,11 @@ define([ allowZoomOut = false, allowZoomIn = true; - (function () { - var style = document.documentElement.style, - transitionEnabled = style.transition !== undefined || - style.WebkitTransition !== undefined || - style.MozTransition !== undefined || - style.MsTransition !== undefined || - style.OTransition !== undefined; - })(); + transitionEnabled = document.documentElement.style.transition !== undefined || + document.documentElement.style.WebkitTransition !== undefined || + document.documentElement.style.MozTransition !== undefined || + document.documentElement.style.MsTransition !== undefined || + document.documentElement.style.OTransition !== undefined; /** * Return width and height of original image @@ -314,7 +311,7 @@ define([ ratio, dimentions = {}; - if (allowZoomIn && (!transitionEnabled && !transitionActive) && (isTouchEnabled || + if (allowZoomIn && (!transitionEnabled || !transitionActive) && (isTouchEnabled || !$(zoomInButtonSelector).hasClass(zoomInDisabled))) { $image = $(fullscreenImageSelector); imgOriginalSize = getImageSize($image[0]); @@ -387,7 +384,7 @@ define([ ratio, fitIntoParent; - if (allowZoomOut && (!transitionEnabled && !transitionActive) && (isTouchEnabled || + if (allowZoomOut && (!transitionEnabled || !transitionActive) && (isTouchEnabled || !$(zoomOutButtonSelector).hasClass(zoomOutDisabled))) { allowZoomIn = true; $image = $(fullscreenImageSelector); @@ -679,7 +676,7 @@ define([ if ($image.hasClass(imageDraggableClass)) { $image.removeClass(imageDraggableClass); } - } else if (gallery.fullScreen && (!transitionEnabled && !transitionActive)) { + } else if (gallery.fullScreen && (!transitionEnabled || !transitionActive)) { imagePosY = getTop($image); imagePosX = $image.offset().left; @@ -719,7 +716,7 @@ define([ var clientX, clientY; - if (gallery.fullScreen && isDragActive && (!transitionEnabled && !transitionActive)) { + if (gallery.fullScreen && isDragActive && (!transitionEnabled || !transitionActive)) { if (allowZoomOut && !$image.hasClass(imageDraggableClass)) { $image.addClass(imageDraggableClass); From aa53fa67b3bbfcc65777b84b034af901ea7c32f8 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 1 Dec 2020 18:51:41 -0600 Subject: [PATCH 171/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Test/StorefrontAutoGeneratedCouponCodeTest.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index 1c63796827785..571bb30e34dd4 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -101,11 +101,6 @@ <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyPayment"/> <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> <waitForElement selector="{{CheckoutSuccessMainSection.success}}" time="30" stepKey="waitForLoadSuccessPage"/> - <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue"> - <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> - <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> - </actionGroup> - <reloadPage stepKey="refreshPage1"/> <!-- Step: 9-10. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage1"/> @@ -151,6 +146,11 @@ <!-- Step; 15-16. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage3"/> <waitForPageLoad stepKey="waitForPageLoad5"/> + <!-- Start the usage processing consumer --> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue"> + <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> + <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> + </actionGroup> <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule3"> <argument name="product" value="$$createSimpleProduct$$"/> <argument name="couponCode" value="{$couponCode}"/> From 4a5c877c632bfce25e23c655b6c555fb435ff1ed Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 1 Dec 2020 18:52:34 -0600 Subject: [PATCH 172/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml index 4813d8aefdb8d..5ee98b49bd007 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleQueueData.xml @@ -10,6 +10,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="SalesRuleConsumerData"> <data key="consumerName">sales.rule.update.coupon.usage</data> - <data key="messageLimit">3</data> + <data key="messageLimit">10</data> </entity> </entities> From cdc838667b98cdc8e3bad1b74435fcbe23f04d49 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 1 Dec 2020 18:58:05 -0600 Subject: [PATCH 173/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index 571bb30e34dd4..1c9e6b99d073e 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -58,7 +58,7 @@ <see selector="{{AdminCartPriceRulesFormSection.successMessage}}" userInput="Message is added to queue, wait to get your coupons soon" stepKey="seeSuccessMessage"/> - <!-- Start message queue for export consumer and coupon processing --> + <!-- Start message queue for export consumer --> <actionGroup ref="CliConsumerStartActionGroup" stepKey="startMessageQueue"> <argument name="consumerName" value="{{AdminCodeGeneratorMessageConsumerData.consumerName}}"/> <argument name="maxMessages" value="{{AdminCodeGeneratorMessageConsumerData.messageLimit}}"/> @@ -143,14 +143,15 @@ <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder1"/> <waitForElement selector="{{CheckoutSuccessMainSection.success}}" time="30" stepKey="waitForLoadSuccessPage1"/> - <!-- Step; 15-16. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> - <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage3"/> - <waitForPageLoad stepKey="waitForPageLoad5"/> <!-- Start the usage processing consumer --> <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue"> <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> </actionGroup> + + <!-- Step; 15-16. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> + <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage3"/> + <waitForPageLoad stepKey="waitForPageLoad5"/> <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule3"> <argument name="product" value="$$createSimpleProduct$$"/> <argument name="couponCode" value="{$couponCode}"/> From 4f4067bdfa1b33941d058eac93d18a949da7b6bb Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Tue, 1 Dec 2020 18:59:39 -0600 Subject: [PATCH 174/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index 1c9e6b99d073e..36e70d4f80561 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -105,7 +105,6 @@ <!-- Step: 9-10. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage1"/> <waitForPageLoad stepKey="waitForPageLoad3"/> - <reloadPage stepKey="refreshPage2"/> <actionGroup ref="ApplyCartRuleOnStorefrontActionGroup" stepKey="applyCartPriceRule1"> <argument name="product" value="$$createSimpleProduct$$"/> <argument name="couponCode" value="{$couponCode}"/> From 7dcd88bd75b83a0a7016b36738462a2e256d8d20 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 2 Dec 2020 10:38:58 +0200 Subject: [PATCH 175/346] added selector AdminOrdersGridSection.orderIdByIncrementId Please enter the commit message for your changes. Lines starting --- .../Mftf/Section/AdminOrdersGridSection.xml | 1 + .../Test/Mftf/Section/OrdersGridSection.xml | 1 + ...ssOrdersCancelCompleteAndClosedAPITest.xml | 27 +++++++++++++------ 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml index 02878e79f3d70..55cd30f1caf2e 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrdersGridSection.xml @@ -41,5 +41,6 @@ <element name="viewLink" type="text" selector="//td/div[contains(.,'{{orderID}}')]/../..//a[@class='action-menu-item']" parameterized="true"/> <element name="selectOrderID" type="checkbox" selector="//td/div[text()='{{orderId}}']/../preceding-sibling::td//input" parameterized="true" timeout="60"/> <element name="orderId" type="text" selector="//table[contains(@class, 'data-grid')]//div[contains(text(), '{{orderId}}')]" parameterized="true"/> + <element name="orderIdByIncrementId" type="text" selector="//input[@class='admin__control-checkbox' and @value={{incrId}}]/parent::label/parent::td/following-sibling::td" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml index a6b856f9f814f..02e11ec62e949 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml @@ -30,5 +30,6 @@ <element name="removeItems" type="select" selector="//span[text()='{{arg}}']/parent::td/following-sibling::td/select[@class='admin__control-select']" parameterized="true"/> <element name="applyCoupon" type="input" selector="#coupons:code"/> <element name="submitOrder" type="button" selector="#submit_order_top_button" timeout="60"/> + </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml index 5ed660b21c6df..e0ecab5947bfb 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml @@ -50,7 +50,7 @@ <createData entity="GuestCart" stepKey="createGuestCartTwo"/> <createData entity="SimpleCartItem" stepKey="addCartItemTwo"> - <requiredEntity createDataKey="createGuestCartTow"/> + <requiredEntity createDataKey="createGuestCartTwo"/> <requiredEntity createDataKey="createSimpleProduct"/> </createData> <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddressTwo"> @@ -71,7 +71,6 @@ </before> <after> <!-- Delete data --> - <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> @@ -103,32 +102,44 @@ <!-- Create CreditMemo for second Order --> <!-- <actionGroup ref="AdminCreateInvoiceAndCreditMemoActionGroup" stepKey="createCreditMemo"/> --> + <!-- <actionGroup ref="AdminOpenOrderByEntityIdActionGroup" stepKey="openOrderOne"> + <argument name="entityId" value="$createGuestCartOne.return$"/> + </actionGroup> + <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderOneId"/> + + <actionGroup ref="AdminOpenOrderByEntityIdActionGroup" stepKey="openOrderTwo"> + <argument name="entityId" value="$createGuestCartTwo.return$"/> + </actionGroup> --> + <!-- Navigate to backend: Go to Sales > Orders --> <actionGroup ref="AdminOrdersPageOpenActionGroup" stepKey="onOrderPage"/> <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFilters"/> + <grabTextFrom selector="{{AdminOrdersGridSection.orderIdByIncrementId($createGuestCartOne.return$)}}" stepKey="getOrderOneId"/> + <grabTextFrom selector="{{AdminOrdersGridSection.orderIdByIncrementId($createGuestCartTwo.return$)}}" stepKey="getOrderTwoId"/> + <!-- Select Mass Action according to dataset: Cancel --> <actionGroup ref="AdminTwoOrderActionOnGridActionGroup" stepKey="massActionCancel"> <argument name="action" value="Cancel"/> - <argument name="orderId" value="$createGuestCartOne.return$"/> - <argument name="secondOrderId" value="$createGuestCartTwo.return$"/> + <argument name="orderId" value="$getOrderOneId"/> + <argument name="secondOrderId" value="$getOrderTwoId"/> </actionGroup> <see userInput="You cannot cancel the order(s)." stepKey="assertOrderCancelMassActionFailMessage"/> <!--Assert first order in orders grid --> <actionGroup ref="AdminOrderFilterByOrderIdAndStatusActionGroup" stepKey="seeFirstOrder"> - <argument name="orderId" value="$createGuestCartOne.return$"/> + <argument name="orderId" value="$getOrderOneId"/> <argument name="orderStatus" value="Complete"/> </actionGroup> - <see userInput="$createGuestCartOne.return$" selector="{{AdminOrdersGridSection.gridCell('1','ID')}}" stepKey="assertFirstOrderID"/> + <see userInput="$getOrderOneId" selector="{{AdminOrdersGridSection.gridCell('1','ID')}}" stepKey="assertFirstOrderID"/> <see userInput="Complete" selector="{{AdminOrdersGridSection.gridCell('1','Status')}}" stepKey="assertFirstOrderStatus"/> <!--Assert second order in orders grid --> <actionGroup ref="AdminOrderFilterByOrderIdAndStatusActionGroup" stepKey="seeSecondOrder"> - <argument name="orderId" value="$createGuestCartTwo.return$"/> + <argument name="orderId" value="$getOrderTwoId"/> <argument name="orderStatus" value="Closed"/> </actionGroup> - <see userInput="$createGuestCartTwo.return$" selector="{{AdminOrdersGridSection.gridCell('1','ID')}}" stepKey="assertSecondOrderID"/> + <see userInput="$getOrderTwoId" selector="{{AdminOrdersGridSection.gridCell('1','ID')}}" stepKey="assertSecondOrderID"/> <see userInput="Closed" selector="{{AdminOrdersGridSection.gridCell('1','Status')}}" stepKey="assertSecondStatus"/> </test> </tests> From 732c6ff48720740fa0e399f2b1d85b198dd41c9e Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 2 Dec 2020 12:07:37 +0200 Subject: [PATCH 176/346] refactored --- ...ssOrdersCancelCompleteAndClosedAPITest.xml | 42 +------------------ 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml index e0ecab5947bfb..85f2fde4d1871 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml @@ -47,7 +47,6 @@ <requiredEntity createDataKey="createGuestCartOne"/> </createData> - <createData entity="GuestCart" stepKey="createGuestCartTwo"/> <createData entity="SimpleCartItem" stepKey="addCartItemTwo"> <requiredEntity createDataKey="createGuestCartTwo"/> @@ -69,56 +68,19 @@ </createData> </before> + <after> - <!-- Delete data --> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> - <!-- Create first order --> - <!-- <actionGroup ref="CreateOrderActionGroup" stepKey="createFirstOrder"> - <argument name="product" value="$$createProduct$$"/> - <argument name="customer" value="$$createCustomer$$"/> - </actionGroup> - <grabTextFrom selector="|Order # (\d+)|" stepKey="getFirstOrderId"/> - <assertNotEmpty stepKey="assertOrderIdIsNotEmpty" after="getFirstOrderId"> - <actualResult type="const">$getFirstOrderId</actualResult> - </assertNotEmpty> --> - - <!-- Create Shipment for first Order --> - <!-- <actionGroup ref="AdminCreateInvoiceAndShipmentActionGroup" stepKey="createShipmentForFirstOrder"/> --> - - <!-- Create second order --> - <!-- <actionGroup ref="CreateOrderActionGroup" stepKey="createSecondOrder"> - <argument name="product" value="$$createProduct$$"/> - <argument name="customer" value="$$createCustomer$$"/> - </actionGroup> - <grabTextFrom selector="|Order # (\d+)|" stepKey="getSecondOrderId"/> - <assertNotEmpty stepKey="assertSecondOrderIdIsNotEmpty" after="getSecondOrderId"> - <actualResult type="const">$getSecondOrderId</actualResult> - </assertNotEmpty> --> - - <!-- Create CreditMemo for second Order --> - <!-- <actionGroup ref="AdminCreateInvoiceAndCreditMemoActionGroup" stepKey="createCreditMemo"/> --> - - <!-- <actionGroup ref="AdminOpenOrderByEntityIdActionGroup" stepKey="openOrderOne"> - <argument name="entityId" value="$createGuestCartOne.return$"/> - </actionGroup> - <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderOneId"/> - - <actionGroup ref="AdminOpenOrderByEntityIdActionGroup" stepKey="openOrderTwo"> - <argument name="entityId" value="$createGuestCartTwo.return$"/> - </actionGroup> --> - - <!-- Navigate to backend: Go to Sales > Orders --> <actionGroup ref="AdminOrdersPageOpenActionGroup" stepKey="onOrderPage"/> <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearFilters"/> <grabTextFrom selector="{{AdminOrdersGridSection.orderIdByIncrementId($createGuestCartOne.return$)}}" stepKey="getOrderOneId"/> <grabTextFrom selector="{{AdminOrdersGridSection.orderIdByIncrementId($createGuestCartTwo.return$)}}" stepKey="getOrderTwoId"/> - <!-- Select Mass Action according to dataset: Cancel --> <actionGroup ref="AdminTwoOrderActionOnGridActionGroup" stepKey="massActionCancel"> <argument name="action" value="Cancel"/> <argument name="orderId" value="$getOrderOneId"/> @@ -126,7 +88,6 @@ </actionGroup> <see userInput="You cannot cancel the order(s)." stepKey="assertOrderCancelMassActionFailMessage"/> - <!--Assert first order in orders grid --> <actionGroup ref="AdminOrderFilterByOrderIdAndStatusActionGroup" stepKey="seeFirstOrder"> <argument name="orderId" value="$getOrderOneId"/> <argument name="orderStatus" value="Complete"/> @@ -134,7 +95,6 @@ <see userInput="$getOrderOneId" selector="{{AdminOrdersGridSection.gridCell('1','ID')}}" stepKey="assertFirstOrderID"/> <see userInput="Complete" selector="{{AdminOrdersGridSection.gridCell('1','Status')}}" stepKey="assertFirstOrderStatus"/> - <!--Assert second order in orders grid --> <actionGroup ref="AdminOrderFilterByOrderIdAndStatusActionGroup" stepKey="seeSecondOrder"> <argument name="orderId" value="$getOrderTwoId"/> <argument name="orderStatus" value="Closed"/> From a70dfc91c5842aa8ae497912ac91ca2ca93f5020 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 2 Dec 2020 12:27:56 +0200 Subject: [PATCH 177/346] refactored --- .../Quote/Test/Mftf/Data/CustomerCartData.xml | 6 -- .../Test/Mftf/Metadata/CreditMemoMeta.xml | 2 +- .../Test/Mftf/Section/OrdersGridSection.xml | 1 - .../Test/Mftf/Test/AdminCreateInvoice.xml | 62 ------------------- ...ssOrdersCancelCompleteAndClosedAPITest.xml | 2 + 5 files changed, 3 insertions(+), 70 deletions(-) delete mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml diff --git a/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml b/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml index affebbc07ad61..8c76c4d0dc31a 100755 --- a/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml +++ b/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml @@ -25,10 +25,4 @@ <requiredEntity type="billing_address">BillingAddressTX</requiredEntity> </entity> - <entity name="CustomerOrderPaymentMethod" type="CustomerPaymentInformation"> - <var key="cart_id" entityKey="return" entityType="CustomerCart"/> - <requiredEntity type="payment_method">PaymentMethodCheckMoneyOrder</requiredEntity> - <requiredEntity type="billing_address">BillingAddressTX</requiredEntity> - </entity> - </entities> diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml index 3b500d61b1c35..b051c91ba3b10 100644 --- a/app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/CreditMemoMeta.xml @@ -11,7 +11,7 @@ <operation name="CreateCreditMemo" dataType="CreditMemo" type="create" auth="adminOauth" url="V1/order/{return}/refund" method="POST"> <contentType>application/json</contentType> <object key="cartItem" dataType="CartItem"> - <field key="quote_id">string</field> + <field key="quote_id">string</field> </object> </operation> </operations> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml index 02e11ec62e949..a6b856f9f814f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/OrdersGridSection.xml @@ -30,6 +30,5 @@ <element name="removeItems" type="select" selector="//span[text()='{{arg}}']/parent::td/following-sibling::td/select[@class='admin__control-select']" parameterized="true"/> <element name="applyCoupon" type="input" selector="#coupons:code"/> <element name="submitOrder" type="button" selector="#submit_order_top_button" timeout="60"/> - </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml deleted file mode 100644 index 3dc1c3ed98d03..0000000000000 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoice.xml +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AdminCreateInvoice"> - <annotations> - <features value="Sales"/> - <stories value="1Create an Invoice via the Admin"/> - <title value="1111Admin should be able to create an invoice"/> - <description value="1Admin should be able to create an invoice"/> - <severity value="MAJOR"/> - <testCaseId value="1MAGETWO-72096"/> - <group value="sales"/> - </annotations> - <before> - <createData entity="ApiCategory" stepKey="createCategory"/> - - <createData entity="defaultSimpleProduct" stepKey="createConfigProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - - <createData entity="GuestCart" stepKey="createGuestCart"/> - <createData entity="SimpleCartItem" stepKey="addCartItem"> - <requiredEntity createDataKey="createGuestCart"/> - <requiredEntity createDataKey="createConfigProduct"/> - </createData> - <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddress"> - <requiredEntity createDataKey="createGuestCart"/> - </createData> - <updateData createDataKey="createGuestCart" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformation"> - <requiredEntity createDataKey="createGuestCart"/> - </updateData> - - <createData entity="Invoice" stepKey="invoiceOrder"> - <requiredEntity createDataKey="createGuestCart"/> - </createData> - - <createData entity="Shipment" stepKey="shipOrder"> - <requiredEntity createDataKey="createGuestCart"/> - </createData> - - <createData entity="CreditMemo" stepKey="refundMemo"> - <requiredEntity createDataKey="createGuestCart"/> - </createData> - - </before> - <after> - <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> - <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> - <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> - </after> - - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> - - </test> -</tests> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml index 85f2fde4d1871..5cb54f0fd5613 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml @@ -18,7 +18,9 @@ <group value="sales"/> <group value="mtf_migrated"/> </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> <createData entity="ApiCategory" stepKey="createCategory"/> From a5dd5e99039e17705a42297b14a9a40fcd11d96f Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 2 Dec 2020 12:29:18 +0200 Subject: [PATCH 178/346] refactored --- app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml b/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml index 8c76c4d0dc31a..a14be3b533fa8 100755 --- a/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml +++ b/app/code/Magento/Quote/Test/Mftf/Data/CustomerCartData.xml @@ -24,5 +24,4 @@ <requiredEntity type="payment_method">PaymentMethodCheckMoneyOrder</requiredEntity> <requiredEntity type="billing_address">BillingAddressTX</requiredEntity> </entity> - </entities> From dfad73dbca641d405970f024d53856475be5c242 Mon Sep 17 00:00:00 2001 From: Sergio Vera <svera@adobe.com> Date: Wed, 2 Dec 2020 11:49:04 +0100 Subject: [PATCH 179/346] MC-39542: Change LiveCodeTest php stability test - Check for PHP compatibility using lowest and highest supported PHP versions --- .../Magento/Test/Php/LiveCodeTest.php | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php index aa1f8b1c259a4..f294e2c2f55e1 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php @@ -209,14 +209,14 @@ private function getFullWhitelist() } /** - * Retrieves the lowest PHP version specified in <kbd>composer.json</var> of project. + * Retrieves the lowest and highest PHP version specified in <kbd>composer.json</var> of project. * - * @return string + * @return array */ - private function getLowestPhpVersion(): string + private function getTargetPhpVersions(): array { $composerJson = json_decode(file_get_contents(BP . '/composer.json'), true); - $phpVersion = '7.0'; + $versionsRange = []; if (isset($composerJson['require']['php'])) { $versions = explode('||', $composerJson['require']['php']); @@ -232,12 +232,17 @@ private function getLowestPhpVersion(): string //sort versions usort($versions, 'version_compare'); - $lowestVersion = array_shift($versions); - $versionParts = explode('.', $lowestVersion); - $phpVersion = sprintf('%s.%s', $versionParts[0], $versionParts[1] ?? '0'); + $versionsRange[] = array_shift($versions); + if (!empty($versions)) { + $versionsRange[] = array_pop($versions); + } + foreach ($versionsRange as $key => $version) { + $versionParts = explode('.', $versionsRange[$key]); + $versionsRange[$key] = sprintf('%s.%s', $versionParts[0], $versionParts[1] ?? '0'); + } } - return $phpVersion; + return $versionsRange; } /** @@ -408,7 +413,7 @@ public function testStrictTypes() */ public function testPhpCompatibility() { - $targetVersion = $this->getLowestPhpVersion(); + $targetVersions = $this->getTargetPhpVersions(); $reportFile = self::$reportDir . '/phpcompatibility_report.txt'; $rulesetDir = __DIR__ . '/_files/PHPCompatibilityMagento'; @@ -417,7 +422,11 @@ public function testPhpCompatibility() } $codeSniffer = new PhpCompatibility($rulesetDir, $reportFile, new Wrapper()); - $codeSniffer->setTestVersion($targetVersion); + if (count($targetVersions) > 1) { + $codeSniffer->setTestVersion($targetVersions[0] . '-' . $targetVersions[1]); + } else { + $codeSniffer->setTestVersion($targetVersions[0]); + } $result = $codeSniffer->run( $this->isFullScan() ? $this->getFullWhitelist() : self::getWhitelist(['php', 'phtml']) From c3e897c3516abcc43e80182310de0a21568b0f8a Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Wed, 2 Dec 2020 16:30:38 +0200 Subject: [PATCH 180/346] MC-36779: Product still present in the Wish List after added to order --- .../Magento/Sales/Model/AdminOrder/Create.php | 4 ++-- .../CreateOrderFromEditCustomerPageTest.xml | 13 ++++++------- .../view/adminhtml/web/order/create/scripts.js | 18 +++++++++++++++--- .../Adminhtml/Order/Create/LoadBlockTest.php | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index d7ddd423733a8..935d9111c489d 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -970,7 +970,7 @@ public function applySidebarData($data) $item = $this->getCustomerCart()->getItemById($itemId); if ($item) { $this->moveQuoteItem($item, 'order', $qty); - $data['remove'][$itemId] = 'cart'; + $this->removeItem($itemId, 'cart'); } } } @@ -984,7 +984,7 @@ public function applySidebarData($data) ); if ($item->getId()) { $this->addProduct($item->getProduct(), $item->getBuyRequest()->toArray()); - $data['remove'][$itemId] = 'wishlist'; + $this->removeItem($itemId, 'wishlist'); } } } diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml index 367c50359701c..89a5fe07ced6a 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml @@ -136,15 +136,18 @@ <see selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$$simpleProduct.name$$" stepKey="seeSimpleProductInWishList"/> <see selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$$createConfigProduct.name$$" stepKey="seeConfigurableProductInWishList"/> - <!-- Add products to order from Wish List --> + <!-- Move products to order from Wish List --> <waitForElementVisible selector="{{AdminCreateOrderWishListSection.addProductToOrderCheckBox($$simpleProduct.name$$)}}" stepKey="waitForCheckBoxToVisible"/> <click selector="{{AdminCreateOrderWishListSection.addProductToOrderCheckBox($$simpleProduct.name$$)}}" stepKey="selectProductToAddToOrder"/> + <click selector="{{AdminCustomerCreateNewOrderSection.updateChangesBtn}}" stepKey="clickOnUpdateButton"/> <click selector="{{AdminCreateOrderWishListSection.addConfigProductToOrder($$createConfigProduct.name$$)}}" stepKey="AddConfigurableProductToOrder"/> <waitForElementVisible selector="{{AdminOrderFormConfigureProductSection.optionSelect($$createConfigProductAttribute.default_frontend_label$$)}}" stepKey="waitForConfigurablePopover"/> <selectOption selector="{{AdminOrderFormConfigureProductSection.optionSelect($$createConfigProductAttribute.default_frontend_label$$)}}" userInput="$$getConfigAttributeOption1.label$$" stepKey="selectConfigurableOption"/> <click selector="{{AdminOrderFormConfigureProductSection.ok}}" stepKey="clickOkButton"/> - <click selector="{{AdminCustomerCreateNewOrderSection.updateChangesBtn}}" stepKey="clickOnUpdateButton"/> - <waitForPageLoad stepKey="waitForAdminOrderItemsOrderedSectionPageLoad1"/> + + <!-- After move, assert products are NOT present in Wish List section --> + <dontSee selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$simpleProduct.name$" stepKey="dontSeeSimpleProductInWishList"/> + <dontSee selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$createConfigProduct.name$" stepKey="dontSeeConfigurableProductInWishList"/> <!-- Assert Products in Order item section --> <see selector="{{AdminOrderItemsOrderedSection.productName}}" userInput="$$simpleProduct.name$$" stepKey="seeSimpleProductInOrderItemGrid"/> @@ -171,10 +174,6 @@ <dontSee selector="{{AdminCreateOrderShoppingCartSection.shoppingCartBlock}}" userInput="$$simpleProduct.name$$" stepKey="donSeeProductInShoppingCart"/> <dontSee selector="{{AdminCreateOrderShoppingCartSection.shoppingCartBlock}}" userInput="$$simpleProduct1.name$$" stepKey="dontSeeSecondProductInShoppingCart"/> - <!-- After move, assert products are present in Wish List section --> - <see selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$$simpleProduct.name$$" stepKey="seeSimpleProductInWishList1"/> - <see selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$$createConfigProduct.name$$" stepKey="seeConfigurableProductInWishList1"/> - <!-- After move, assert products are present in order items section --> <see selector="{{AdminOrderItemsOrderedSection.productName}}" userInput="$$simpleProduct.name$$" stepKey="seeSimpleProductInOrderItemGrid1"/> <see selector="{{AdminOrderItemsOrderedSection.productName}}" userInput="$$createConfigProduct.name$$" stepKey="seeConfigProductInOrderItemGrid1"/> 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 ba93f5f88c387..f90ad563331e6 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 @@ -942,7 +942,8 @@ define([ */ sidebarConfigureProduct: function (listType, productId, itemId) { // create additional fields - var params = {}; + var params = {}, + isWishlist = !!itemId; params.reset_shipping = true; params.add_product = productId; this.prepareParams(params); @@ -963,10 +964,18 @@ define([ }.bind(this)); // response handler productConfigure.setOnLoadIFrameCallback(listType, function (response) { + var area = ['items', 'shipping_method', 'billing_method', 'totals', 'giftmessage']; + if (!response.ok) { return; } - this.loadArea(['items', 'shipping_method', 'billing_method', 'totals', 'giftmessage'], true); + if (isWishlist) { + this.removeSidebarItem(itemId, 'wishlist').done(function () { + this.loadArea(area, true); + }.bind(this)); + } else { + this.loadArea(area, true); + } }.bind(this)); // show item configuration itemId = itemId ? itemId : productId; @@ -975,7 +984,10 @@ define([ }, removeSidebarItem: function (id, from) { - this.loadArea(['sidebar_' + from], 'sidebar_data_' + from, {remove_item: id, from: from}); + return this.loadArea(['sidebar_' + from], 'sidebar_data_' + from, { + remove_item: id, + from: from + }); }, itemsUpdate: function () { diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php index 104cc74ec1f9b..529b491269643 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php @@ -225,7 +225,7 @@ public function testAddProductToOrderFromWishList(): void $params = $this->hydrateParams(); $this->dispatchWitParams($params, $post); - $wishlistItems->clear(); + $wishlistItems->clear()->load(); $this->assertEmpty($wishlistItems); $quoteItems = $this->session->getQuote()->getItemsCollection(); $this->assertCount(1, $quoteItems); From 8e1a0aef98b3e6fe3cb6c68c483ac0a22007cf46 Mon Sep 17 00:00:00 2001 From: Sergiy Vasiutynskyi <s.vasiutynskyi@atwix.com> Date: Wed, 2 Dec 2020 17:10:16 +0200 Subject: [PATCH 181/346] Removed usage or changed value of CliIndexerReindexActionGroup action group for Bundle, BundleImportExport, CatalogUrlRewrite, ConfigurableProduct modules --- .../Mftf/Test/AdminAssociateBundleProductToWebsitesTest.xml | 5 +---- .../Mftf/Test/AdminDeleteBundleDynamicPriceProductTest.xml | 4 +--- .../Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml | 4 +--- ...frontAddBundleProductWithZeroPriceToShoppingCartTest.xml | 2 +- ...StorefrontCustomerSearchBundleProductsByKeywordsTest.xml | 2 +- .../Mftf/Test/StorefrontSortBundleProductsByPriceTest.xml | 2 +- ...ynamicBundleProductPricesForCombinationOfOptionsTest.xml | 2 +- .../Test/Mftf/Test/UpdateBundleProductViaImportTest.xml | 6 ++---- .../Test/StorefrontCategoryUrlRewriteDifferentStoreTest.xml | 4 +--- .../Test/Mftf/Test/AdminConfigurableProductLongSkuTest.xml | 4 +--- .../Test/AdminCreateConfigurableProductWithImagesTest.xml | 5 +---- .../Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml | 4 +--- .../Test/StorefrontConfigurableProductChildSearchTest.xml | 4 +--- .../StorefrontConfigurableProductGridViewTest.xml | 4 +--- ...nfigurableProductChildAssignedToSeparateCategoryTest.xml | 4 +--- ...tingByPriceForConfigurableWithCatalogRuleAppliedTest.xml | 4 +--- ...efrontVerifyConfigurableProductLayeredNavigationTest.xml | 5 +---- .../Test/StorefrontVisibilityOfDuplicateProductTest.xml | 4 +--- 18 files changed, 19 insertions(+), 50 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAssociateBundleProductToWebsitesTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAssociateBundleProductToWebsitesTest.xml index f73941c375a41..8818fadc1d10c 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAssociateBundleProductToWebsitesTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAssociateBundleProductToWebsitesTest.xml @@ -42,10 +42,7 @@ <requiredEntity createDataKey="createSimpleProduct"/> </createData> - <!-- Reindex --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!-- Login as admin --> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteBundleDynamicPriceProductTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteBundleDynamicPriceProductTest.xml index 8b50fffec091f..6924e389451cd 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteBundleDynamicPriceProductTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminDeleteBundleDynamicPriceProductTest.xml @@ -36,9 +36,7 @@ <requiredEntity createDataKey="createSimpleProduct"/> </createData> <!-- TODO: Remove this action when MC-37719 will be fixed --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexInvalidatedIndices"> - <argument name="indices" value="cataloginventory_stock"/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindexInvalidatedIndices"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> </before> <after> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml index f8f98384ee8da..0474de1144f4e 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/MassEnableDisableBundleProductsTest.xml @@ -133,9 +133,7 @@ <click selector="{{AdminProductFiltersSection.enable}}" stepKey="ClickOnEnable"/> <!--Clear Cache - reindex - resets products according to enabled/disabled view--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml index 93fac3171e9fb..b68171ba49825 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml @@ -41,7 +41,7 @@ <requiredEntity createDataKey="apiSimple"/> </createData> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> + <argument name="indices" value="cataloginventory_stock"/> </actionGroup> </before> <after> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml index 5997cdc14ade8..52cd91385a4b2 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml @@ -40,7 +40,7 @@ <requiredEntity createDataKey="createSimpleProductTwo"/> </createData> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> + <argument name="indices" value="cataloginventory_stock"/> </actionGroup> </before> <after> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontSortBundleProductsByPriceTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontSortBundleProductsByPriceTest.xml index 7049299987dff..d127f18355643 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontSortBundleProductsByPriceTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontSortBundleProductsByPriceTest.xml @@ -96,7 +96,7 @@ <!-- Perform CLI reindex --> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> + <argument name="indices" value="cataloginventory_stock catalog_product_price"/> </actionGroup> </before> <after> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml index 24c481c9ddcb2..3a7550b1484f0 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml @@ -168,7 +168,7 @@ <see userInput="You saved the configuration." selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccess"/> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> + <argument name="indices" value="cataloginventory_stock"/> </actionGroup> </before> <after> diff --git a/app/code/Magento/BundleImportExport/Test/Mftf/Test/UpdateBundleProductViaImportTest.xml b/app/code/Magento/BundleImportExport/Test/Mftf/Test/UpdateBundleProductViaImportTest.xml index 515c2bc56f067..6ddce634ec957 100644 --- a/app/code/Magento/BundleImportExport/Test/Mftf/Test/UpdateBundleProductViaImportTest.xml +++ b/app/code/Magento/BundleImportExport/Test/Mftf/Test/UpdateBundleProductViaImportTest.xml @@ -42,7 +42,7 @@ <argument name="tags" value="full_page"/> </actionGroup> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="indexerReindexAfterCreate"> - <argument name="indices" value=""/> + <argument name="indices" value="catalog_product_price"/> </actionGroup> <!-- Check Bundle product is visible on the storefront--> @@ -63,9 +63,7 @@ <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCacheAfterUpdate"> <argument name="tags" value="full_page"/> </actionGroup> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="indexerReindexAfterUpdate"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="indexerReindexAfterUpdate"/> <!-- Check Bundle product is still visible on the storefront--> <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="openCategoryPageAfterUpdate"> diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/StorefrontCategoryUrlRewriteDifferentStoreTest.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/StorefrontCategoryUrlRewriteDifferentStoreTest.xml index 776b5b9b70f33..783d9fa31c996 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/StorefrontCategoryUrlRewriteDifferentStoreTest.xml +++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/StorefrontCategoryUrlRewriteDifferentStoreTest.xml @@ -31,9 +31,7 @@ <argument name="storeView" value="customStoreFR"/> </actionGroup> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="indexerReindexAfterCreate"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="indexerReindexAfterCreate"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCacheBefore"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductLongSkuTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductLongSkuTest.xml index f8cd1760788a8..4915a17c738a4 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductLongSkuTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductLongSkuTest.xml @@ -91,9 +91,7 @@ <see selector="{{AdminProductFormConfigurationsSection.currentVariationsPriceCells}}" userInput="{{ProductWithLongNameSku.price}}" stepKey="seeConfigurationsPrice"/> <!--Run re-index task--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!--Assert storefront category list page--> <amOnPage url="/" stepKey="amOnStorefront"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithImagesTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithImagesTest.xml index 120734d679d09..4984d296df5d0 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithImagesTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithImagesTest.xml @@ -131,10 +131,7 @@ <!-- Save product --> <actionGroup ref="SaveConfigurableProductAddToCurrentAttributeSetActionGroup" stepKey="saveProduct"/> - <!--Run re-index task--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!-- Assert configurable product in category --> <amOnPage url="$$createCategory.name$$.html" stepKey="amOnCategoryPage"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml index e34bf7c22f06b..1b8dffbd3ac68 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/EndToEndB2CLoggedInUserTest.xml @@ -78,9 +78,7 @@ <!-- Reindex invalidated indices after product attribute has been created/deleted --> <magentoCron groups="index" stepKey="reindexInvalidatedIndices"/> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexAll"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindexAll"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml index 4ad2d0dc936eb..ca3065c13ea67 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductChildSearchTest.xml @@ -144,9 +144,7 @@ <magentoCron groups="index" stepKey="reindexInvalidatedIndices"/> </after> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexAll"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindexAll"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductViewTest/StorefrontConfigurableProductGridViewTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductViewTest/StorefrontConfigurableProductGridViewTest.xml index e20a6dcfa09b8..81a083c5da068 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductViewTest/StorefrontConfigurableProductGridViewTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductViewTest/StorefrontConfigurableProductGridViewTest.xml @@ -27,9 +27,7 @@ <argument name="category" value="$$createCategory$$"/> </actionGroup> <!-- TODO: REMOVE AFTER FIX MC-21717 --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value="eav"/> </actionGroup> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontShouldSeeOnlyConfigurableProductChildAssignedToSeparateCategoryTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontShouldSeeOnlyConfigurableProductChildAssignedToSeparateCategoryTest.xml index 3519503c1e287..65ba89d5efb1f 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontShouldSeeOnlyConfigurableProductChildAssignedToSeparateCategoryTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontShouldSeeOnlyConfigurableProductChildAssignedToSeparateCategoryTest.xml @@ -112,9 +112,7 @@ <argument name="categoryName" value="$$secondCategory.name$$"/> </actionGroup> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexSearchIndex"> - <argument name="indices" value="catalogsearch_fulltext"/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindexSearchIndex"/> <!-- Go to storefront to view child product --> <actionGroup ref="StorefrontNavigateCategoryPageActionGroup" stepKey="goToSecondCategoryStorefront"> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontSortingByPriceForConfigurableWithCatalogRuleAppliedTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontSortingByPriceForConfigurableWithCatalogRuleAppliedTest.xml index 363a8ea4d4fd6..9cbe134116e51 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontSortingByPriceForConfigurableWithCatalogRuleAppliedTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontSortingByPriceForConfigurableWithCatalogRuleAppliedTest.xml @@ -153,9 +153,7 @@ <argument name="discountAmount" value="{{CatalogRuleByPercentWith96Amount.discount_amount}}"/> </actionGroup> <actionGroup ref="AdminCatalogPriceRuleSaveAndApplyActionGroup" stepKey="saveAndApplyCatalogPriceRule"/> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexIndices"> - <argument name="indices" value="catalogsearch_fulltext catalog_category_product catalog_product_price catalogrule_rule"/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindexIndices"/> <actionGroup ref="CliCacheCleanActionGroup" stepKey="fullCache"> <argument name="tags" value="full_page"/> </actionGroup> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVerifyConfigurableProductLayeredNavigationTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVerifyConfigurableProductLayeredNavigationTest.xml index 9b046d5c71cfc..c5a40be952e2a 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVerifyConfigurableProductLayeredNavigationTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVerifyConfigurableProductLayeredNavigationTest.xml @@ -136,10 +136,7 @@ <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="clickOnSaveButton"/> <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the product." stepKey="messageYouSavedTheProductIsShown"/> - <!--Run re-index task--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!--Open Category in Store Front and select product attribute option from sidebar --> <actionGroup ref="SelectStorefrontSideBarAttributeOption" stepKey="selectStorefrontProductAttributeOption"> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVisibilityOfDuplicateProductTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVisibilityOfDuplicateProductTest.xml index 79705e679fb78..8cd4489ba2a36 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVisibilityOfDuplicateProductTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontVisibilityOfDuplicateProductTest.xml @@ -192,9 +192,7 @@ <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="generateConfigsForDuplicatedProduct"/> <waitForPageLoad stepKey="waitForDuplicatedProductPageLoad"/> <actionGroup ref="SaveProductFormActionGroup" stepKey="saveDuplicatedProduct"/> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> From c6b97a0d210acbcd3863917b48e65c9dc7f1ac77 Mon Sep 17 00:00:00 2001 From: Oleksandr Iegorov <oiegorov@magento.com> Date: Wed, 2 Dec 2020 09:26:31 -0600 Subject: [PATCH 182/346] MC-29335: Missing paid orders and lock wait timeouts in Guest Checkout --- .../Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml index 36e70d4f80561..18de326a2919d 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAutoGeneratedCouponCodeTest.xml @@ -102,6 +102,12 @@ <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> <waitForElement selector="{{CheckoutSuccessMainSection.success}}" time="30" stepKey="waitForLoadSuccessPage"/> + <!-- Start the usage processing consumer --> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue1"> + <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> + <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> + </actionGroup> + <!-- Step: 9-10. Open the Product Page, add the product to Cart, go to Shopping Cart and Apply the same coupon code --> <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.name$$)}}" stepKey="openProductPage1"/> <waitForPageLoad stepKey="waitForPageLoad3"/> @@ -143,7 +149,7 @@ <waitForElement selector="{{CheckoutSuccessMainSection.success}}" time="30" stepKey="waitForLoadSuccessPage1"/> <!-- Start the usage processing consumer --> - <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue"> + <actionGroup ref="CliConsumerStartActionGroup" stepKey="startUsageProcessingMessageQueue2"> <argument name="consumerName" value="{{SalesRuleConsumerData.consumerName}}"/> <argument name="maxMessages" value="{{SalesRuleConsumerData.messageLimit}}"/> </actionGroup> From 19c7e10ccb0b6b6f43dd7931394ca0156c756c8b Mon Sep 17 00:00:00 2001 From: saphaljha <saphal.jha@krishtechnolabs.com> Date: Wed, 2 Dec 2020 23:03:56 +0530 Subject: [PATCH 183/346] Removed header from group product grid --- .../Ui/DataProvider/Product/Form/Modifier/Grouped.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php b/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php index 3ea8c6eb3c2b9..12a21a4ebd04b 100644 --- a/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php +++ b/app/code/Magento/GroupedProduct/Ui/DataProvider/Product/Form/Modifier/Grouped.php @@ -562,6 +562,7 @@ protected function fillMeta() 'fit' => true, 'label' => __('Thumbnail'), 'sortOrder' => 20, + 'labelVisible' => false, ], ], ], @@ -586,6 +587,7 @@ protected function fillMeta() 'validation' => [ 'validate-number' => true, ], + 'labelVisible' => false, ], ], ], @@ -601,7 +603,8 @@ protected function fillMeta() 'elementTmpl' => 'Magento_GroupedProduct/components/position', 'sortOrder' => 90, 'fit' => true, - 'dataScope' => 'positionCalculated' + 'dataScope' => 'positionCalculated', + 'labelVisible' => false, ], ], ], @@ -660,6 +663,7 @@ protected function getTextColumn($dataScope, $fit, Phrase $label, $sortOrder) 'fit' => $fit, 'label' => $label, 'sortOrder' => $sortOrder, + 'labelVisible' => false, ], ], ], From d4e1641188e841885329fa2a8adb0cefd4b44879 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 3 Dec 2020 13:35:51 +0200 Subject: [PATCH 184/346] refactored AdminApplyTierPriceToProductWithPercentageDiscountTest --- .../Catalog/Test/Mftf/Data/TierPriceData.xml | 6 +++ ...iceToProductWithPercentageDiscountTest.xml | 43 +++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml index 731754ef01959..b763fda489b20 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Data/TierPriceData.xml @@ -80,4 +80,10 @@ <data key="quantity">1</data> <var key="sku" entityType="product" entityKey="sku" /> </entity> + <entity name="tierPrice01PercentDiscount" type="data"> + <data key="website">All Websites [USD]</data> + <data key="customer_group">ALL GROUPS</data> + <data key="price">0.1</data> + <data key="qty">1</data> + </entity> </entities> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml index 45284e69a54e0..37a7e461c2869 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml @@ -23,6 +23,7 @@ <requiredEntity createDataKey="createCategory"/> <field key="price">100</field> </createData> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdminInBefore"/> </before> <after> <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> @@ -31,29 +32,45 @@ <actionGroup ref="ResetProductGridToDefaultViewActionGroup" stepKey="resetGridToDefaultKeywordSearch"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </after> - <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="loginAsAdmin"/> <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProduct1"> <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> - <scrollToTopOfPage stepKey="scrollToTopOfPage"/> - <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton"/> - <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForCustomerGroupPriceAddButton"/> - <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAndpercent"/> - <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" userInput="1" stepKey="fillProductTierPriceQtyInput"/> - <selectOption selector="{{AdminProductFormAdvancedPricingSection.productTierPriceValueTypeSelect('0')}}" userInput="Discount" stepKey="selectProductTierPriceValueType"/> - <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('0')}}" userInput="0.1" stepKey="selectProductTierPricePriceInput"/> - <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton"/> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="scrollToTopOfPage"/> + <actionGroup ref="AdminProductFormOpenAdvancedPricingDialogActionGroup" stepKey="clickOnAdvancedPricingButton"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAndpercente"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="fillProductTierPriceQtyInput"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectProductTierPriceValueType"/> + + <actionGroup ref="AdminProductFormAdvancedPricingAddTierPriceActionGroup" stepKey="selectProductTierPricePriceInput"> + <argument name="website" value="{{tierPrice01PercentDiscount.website}}"/> + <argument name="customerGroup" value="{{tierPrice01PercentDiscount.customer_group}}"/> + <argument name="quantity" value="{{tierPrice01PercentDiscount.qty}}"/> + <argument name="priceType" value="Discount"/> + <argument name="amount" value="{{tierPrice01PercentDiscount.price}}"/> + </actionGroup> + + <actionGroup ref="AdminProductFormDoneAdvancedPricingDialogActionGroup" stepKey="clickDoneButton"/> <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct1"/> - <amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.sku$$)}}" stepKey="goProductPageOnStorefront"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="goProductPageOnStorefront"> + <argument name="productUrl" value="$$createSimpleProduct.sku$$"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForPageLoad1"/> <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('99.90')}}" stepKey="assertProductFinalPriceProductPage"/> <seeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('Regular Price')}}" stepKey="assertRegularPriceProductPage"/> <seeElement selector="{{StorefrontCategoryProductSection.productPriceOld('100')}}" stepKey="assertRegularPriceAmountProductPage"/> - <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="navigateToCategoryPage"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + + <actionGroup ref="StorefrontNavigateCategoryPageActionGroup" stepKey="navigateToCategoryPage"> + <argument name="category" value="$createCategory$"/> + </actionGroup> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForPageLoad2"/> <seeElement selector="{{StorefrontCategoryProductSection.productPriceFinal('99.90')}}" stepKey="assertProductFinalPriceCategoryPage"/> <seeElement selector="{{StorefrontCategoryProductSection.productPriceLabel('Regular Price')}}" stepKey="assertRegularPriceLabelCategoryPage"/> <seeElement selector="{{StorefrontCategoryProductSection.productPriceOld('100')}}" stepKey="assertRegularPriceAmountCategoryPage"/> From 00fa24651f2c7c61b7bc78f2b74173ae22633dda Mon Sep 17 00:00:00 2001 From: Sergiy Vasiutynskyi <s.vasiutynskyi@atwix.com> Date: Thu, 3 Dec 2020 13:36:16 +0200 Subject: [PATCH 185/346] Updated value of CliIndexerReindexActionGroup action for failed test --- ...orefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml | 2 +- .../StorefrontCustomerSearchBundleProductsByKeywordsTest.xml | 3 ++- ...fyDynamicBundleProductPricesForCombinationOfOptionsTest.xml | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml index b68171ba49825..88f992e698181 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontAddBundleProductWithZeroPriceToShoppingCartTest.xml @@ -41,7 +41,7 @@ <requiredEntity createDataKey="apiSimple"/> </createData> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value="cataloginventory_stock"/> + <argument name="indices" value="cataloginventory_stock catalog_product_price"/> </actionGroup> </before> <after> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml index 52cd91385a4b2..f7bce778cc0d8 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontCustomerSearchBundleProductsByKeywordsTest.xml @@ -39,8 +39,9 @@ <requiredEntity createDataKey="fixedBundleOption"/> <requiredEntity createDataKey="createSimpleProductTwo"/> </createData> + <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value="cataloginventory_stock"/> + <argument name="indices" value="cataloginventory_stock catalog_product_price"/> </actionGroup> </before> <after> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml index 3a7550b1484f0..927cebdf7e508 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDynamicBundleProductPricesForCombinationOfOptionsTest.xml @@ -168,7 +168,7 @@ <see userInput="You saved the configuration." selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccess"/> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value="cataloginventory_stock"/> + <argument name="indices" value="cataloginventory_stock catalog_product_price"/> </actionGroup> </before> <after> From fe39fba308b4be8b320dda5d84a50af5919a931a Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 3 Dec 2020 13:43:05 +0200 Subject: [PATCH 186/346] added comment --- .../AdminApplyTierPriceToProductWithPercentageDiscountTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml index 37a7e461c2869..594eb320e439a 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml @@ -44,6 +44,7 @@ <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="scrollToTopOfPage"/> <actionGroup ref="AdminProductFormOpenAdvancedPricingDialogActionGroup" stepKey="clickOnAdvancedPricingButton"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAndpercente"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForCustomerGroupPriceAddButton"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="fillProductTierPriceQtyInput"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectProductTierPriceValueType"/> From 3163fae9967c1a429d6dde46d6c8133acc4b5f34 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Thu, 3 Dec 2020 09:56:39 -0600 Subject: [PATCH 187/346] MC-38951: Images positions are inconsistent across store-views if images were added in a store-view level - Fix images positions for default scope if image were added in store view level --- .../Model/Product/Gallery/CreateHandler.php | 39 ++++++++--- .../Model/Import/Product.php | 11 ++- .../Import/Product/MediaGalleryProcessor.php | 6 +- ...uteMediaGalleryManagementInterfaceTest.php | 18 +++-- .../Helper/Form/Gallery/ContentTest.php | 2 +- .../Block/Product/View/GalleryTest.php | 2 +- .../Product/Gallery/UpdateHandlerTest.php | 67 +++++++++++++++++++ 7 files changed, 126 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php index 5a9d53ce80cf8..7a1bd21d78182 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/CreateHandler.php @@ -267,29 +267,50 @@ protected function processNewAndExistingImages($product, array &$images) { foreach ($images as &$image) { if (empty($image['removed'])) { + $isNew = empty($image['value_id']); $data = $this->processNewImage($product, $image); - if (!$product->isObjectNew()) { - $this->resourceModel->deleteGalleryValueInStore( - $image['value_id'], - $product->getData($this->metadata->getLinkField()), - $product->getStoreId() - ); - } // Add per store labels, position, disabled $data['value_id'] = $image['value_id']; $data['label'] = isset($image['label']) ? $image['label'] : ''; - $data['position'] = isset($image['position']) ? (int)$image['position'] : 0; + $data['position'] = isset($image['position']) && $image['position'] !== '' + ? (int)$image['position'] + : null; $data['disabled'] = isset($image['disabled']) ? (int)$image['disabled'] : 0; $data['store_id'] = (int)$product->getStoreId(); $data[$this->metadata->getLinkField()] = (int)$product->getData($this->metadata->getLinkField()); - $this->resourceModel->insertGalleryValueInStore($data); + $this->saveGalleryStoreValue($product, $data); + if ($isNew && $data['store_id'] !== Store::DEFAULT_STORE_ID) { + $dataForDefaultScope = $data; + $dataForDefaultScope['store_id'] = Store::DEFAULT_STORE_ID; + $dataForDefaultScope['disabled'] = 0; + $dataForDefaultScope['label'] = null; + $this->saveGalleryStoreValue($product, $dataForDefaultScope); + } } } } + /** + * Save media gallery store value + * + * @param Product $product + * @param array $data + */ + private function saveGalleryStoreValue(Product $product, array $data): void + { + if (!$product->isObjectNew()) { + $this->resourceModel->deleteGalleryValueInStore( + $data['value_id'], + $data[$this->metadata->getLinkField()], + $data['store_id'] + ); + } + $this->resourceModel->insertGalleryValueInStore($data); + } + /** * Processes image as new. * diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 428961aa6ddf6..13b7cbc2dfd2a 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1807,7 +1807,7 @@ protected function _saveProducts() if ($column === self::COL_MEDIA_IMAGE) { $rowData[$column][] = $uploadedFile; } - $mediaGallery[$storeId][$rowSku][$uploadedFile] = [ + $mediaGalleryStoreData = [ 'attribute_id' => $this->getMediaGalleryAttributeId(), 'label' => isset($rowLabels[$column][$columnImageKey]) ? $rowLabels[$column][$columnImageKey] @@ -1817,6 +1817,15 @@ protected function _saveProducts() ? $imageHiddenStates[$columnImage] : '0', 'value' => $uploadedFile, ]; + $mediaGallery[$storeId][$rowSku][$uploadedFile] = $mediaGalleryStoreData; + // Add record for default scope if it does not exist + if (!($mediaGallery[Store::DEFAULT_STORE_ID][$rowSku][$uploadedFile] ?? [])) { + //Set label and disabled values to their default values + $mediaGalleryStoreData['label'] = null; + $mediaGalleryStoreData['disabled'] = 0; + $mediaGallery[Store::DEFAULT_STORE_ID][$rowSku][$uploadedFile] = $mediaGalleryStoreData; + } + } } } diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/MediaGalleryProcessor.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/MediaGalleryProcessor.php index d4694b72ba64f..c838688c1c4f8 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/MediaGalleryProcessor.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/MediaGalleryProcessor.php @@ -12,6 +12,7 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\EntityManager\MetadataPool; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; +use Magento\Store\Model\Store; /** * Process and saves images during import. @@ -259,7 +260,10 @@ private function prepareMediaGalleryValueData( $position = $data['position']; $storeId = $data['store_id']; $mediaGalleryValueData[$index]['value_id'] = $productIdMediaValueIdMap[$productId][$value]; - $mediaGalleryValueData[$index]['position'] = $position + ($lastPositions[$storeId][$productId] ?? 0); + $lastPosition = $lastPositions[$storeId][$productId] + ?? $lastPositions[Store::DEFAULT_STORE_ID][$productId] + ?? 0; + $mediaGalleryValueData[$index]['position'] = $position + $lastPosition; unset($mediaGalleryValueData[$index]['value']); } return $mediaGalleryValueData; diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php index ba12a02cb5b1f..09987457e3c56 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductAttributeMediaGalleryManagementInterfaceTest.php @@ -235,8 +235,8 @@ public function testCreateWithNotDefaultStoreId() $this->assertEquals($updatedImage['file'], $targetProduct->getData('image')); // No values for default store view were provided $this->assertNull($updatedImage['label_default']); - $this->assertNull($updatedImage['position_default']); - $this->assertNull($updatedImage['disabled_default']); + $this->assertEquals(1, $updatedImage['position_default']); + $this->assertEquals(0, $updatedImage['disabled_default']); } /** @@ -483,7 +483,9 @@ public function testCreateThrowsExceptionIfProvidedImageHasWrongMimeType() public function testCreateThrowsExceptionIfTargetProductDoesNotExist() { $this->expectException(\Exception::class); - $this->expectExceptionMessage('The product that was requested doesn\'t exist. Verify the product and try again.'); + $this->expectExceptionMessage( + 'The product that was requested doesn\'t exist. Verify the product and try again.' + ); $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/wrong_product_sku/media'; @@ -538,7 +540,9 @@ public function testCreateThrowsExceptionIfProvidedImageNameContainsForbiddenCha public function testUpdateThrowsExceptionIfTargetProductDoesNotExist() { $this->expectException(\Exception::class); - $this->expectExceptionMessage('The product that was requested doesn\'t exist. Verify the product and try again.'); + $this->expectExceptionMessage( + 'The product that was requested doesn\'t exist. Verify the product and try again.' + ); $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong_product_sku/media' . '/' . 'wrong-sku'; @@ -592,7 +596,9 @@ public function testUpdateThrowsExceptionIfThereIsNoImageWithGivenId() public function testDeleteThrowsExceptionIfTargetProductDoesNotExist() { $this->expectException(\Exception::class); - $this->expectExceptionMessage('The product that was requested doesn\'t exist. Verify the product and try again.'); + $this->expectExceptionMessage( + 'The product that was requested doesn\'t exist. Verify the product and try again.' + ); $this->deleteServiceInfo['rest']['resourcePath'] = '/V1/products/wrong_product_sku/media/9999'; $requestData = [ @@ -782,6 +788,6 @@ public function testAddProductVideo() $this->assertEquals(1, $updatedImage['position']); $this->assertEquals(0, $updatedImage['disabled']); $this->assertStringStartsWith('/t/e/test_image', $updatedImage['file']); - $this->assertEquals($videoContent, array_intersect($updatedImage, $videoContent)); + $this->assertEquals($videoContent, array_intersect_key($updatedImage, $videoContent)); } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php index 28c5d435cd038..56a07034bd490 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Helper/Form/Gallery/ContentTest.php @@ -206,7 +206,7 @@ public function imagesPositionStoreViewDataProvider(): array [ 'file' => '/m/a/magento_small_image.jpg', 'label' => null, - 'position' => null, + 'position' => 2, ], ] ], diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php index 2941349a94eaa..bcec3168c7885 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/GalleryTest.php @@ -462,7 +462,7 @@ public function imagesPositionStoreViewDataProvider(): array [ 'img' => '/media/catalog/product/m/a/magento_small_image.jpg', 'caption' => 'Simple Product', - 'position' => null, + 'position' => 2, ], ] ], diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php index 481ec6aeac0f2..f317b9bbf377e 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php @@ -593,6 +593,73 @@ public function updateImageDataProvider(): array ]; } + /** + * Tests that images positions are inconsistent across store-views if images were added in a store-view level + * + * @magentoDataFixture Magento/Catalog/_files/product_with_image.php + * @magentoDataFixture Magento/Store/_files/second_store.php + * @return void + */ + public function testAddImageInStoreView(): void + { + $secondStoreId = (int)$this->storeRepository->get('fixture_second_store')->getId(); + $existingImagePath = '/m/a/magento_image.jpg'; + $newImagePath = '/m/a/magento_small_image.jpg'; + $product = $this->getProduct($secondStoreId); + $images = $product->getData('media_gallery')['images']; + $newImage = [ + 'file' => $newImagePath, + 'position' => 2, + 'label' => 'New Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ]; + $images[] = $newImage; + $product->setData('media_gallery', ['images' => $images]); + $this->updateHandler->execute($product); + $product = $this->getProduct(Store::DEFAULT_STORE_ID); + $expectedImages = [ + [ + 'file' => $existingImagePath, + 'label' => 'Image Alt Text', + 'position' => 1 + ], + [ + 'file' => $newImagePath, + 'label' => null, + 'position' => 2 + ], + ]; + $actualImages = array_map( + function (\Magento\Framework\DataObject $item) { + return $item->toArray(['file', 'label', 'position']); + }, + $product->getMediaGalleryImages()->getItems() + ); + $this->assertEquals($expectedImages, array_values($actualImages)); + $product->cleanModelCache(); + $product = $this->getProduct($secondStoreId); + $expectedImages = [ + [ + 'file' => $existingImagePath, + 'label' => 'Image Alt Text', + 'position' => 1 + ], + [ + 'file' => $newImagePath, + 'label' => 'New Image Alt Text', + 'position' => 2 + ], + ]; + $actualImages = array_map( + function (\Magento\Framework\DataObject $item) { + return $item->toArray(['file', 'label', 'position']); + }, + $product->getMediaGalleryImages()->getItems() + ); + $this->assertEquals($expectedImages, array_values($actualImages)); + } + /** * Check product image link and product image exist * From 92e94220d329065708e1e97fe038f5aa2fb022c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Szubert?= <bartlomiejszubert@gmail.com> Date: Thu, 3 Dec 2020 17:36:20 +0100 Subject: [PATCH 188/346] Fix #30724 - Customer Account Edit controller action enforces Page Title to "Account Information" --- app/code/Magento/Customer/Controller/Account/Edit.php | 9 ++++----- .../view/frontend/layout/customer_account_edit.xml | 3 +++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Customer/Controller/Account/Edit.php b/app/code/Magento/Customer/Controller/Account/Edit.php index 7c2b7215a05ef..d61bd4b1a0fcb 100644 --- a/app/code/Magento/Customer/Controller/Account/Edit.php +++ b/app/code/Magento/Customer/Controller/Account/Edit.php @@ -1,17 +1,16 @@ <?php /** - * * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Customer\Controller\Account; -use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; use Magento\Customer\Api\CustomerRepositoryInterface; -use Magento\Framework\Api\DataObjectHelper; use Magento\Customer\Model\Session; -use Magento\Framework\View\Result\PageFactory; +use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Framework\View\Result\PageFactory; class Edit extends \Magento\Customer\Controller\AbstractAccount implements HttpGetActionInterface { @@ -81,10 +80,10 @@ public function execute() \Magento\Customer\Api\Data\CustomerInterface::class ); } + $this->session->setCustomerData($customerDataObject); $this->session->setChangePassword($this->getRequest()->getParam('changepass') == 1); - $resultPage->getConfig()->getTitle()->set(__('Account Information')); return $resultPage; } } diff --git a/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml b/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml index f4dfaa6586b12..e89aa5ab624d9 100644 --- a/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml +++ b/app/code/Magento/Customer/view/frontend/layout/customer_account_edit.xml @@ -7,6 +7,9 @@ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <update handle="customer_account"/> + <head> + <title>Account Information + From 473182be13ae40c0e92548226d567eef041f98ad Mon Sep 17 00:00:00 2001 From: Buba Suma Date: Thu, 3 Dec 2020 12:46:16 -0600 Subject: [PATCH 189/346] MC-38951: Images positions are inconsistent across store-views if images were added in a store-view level - Fix images positions for default scope if image were added in store view level --- .../Product/Gallery/UpdateHandlerTest.php | 123 +++++++++++------- .../Model/Import/ProductTest.php | 85 ++++++++++++ ...port_media_additional_images_storeview.csv | 2 + 3 files changed, 163 insertions(+), 47 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php index f317b9bbf377e..d20bf2907c780 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/UpdateHandlerTest.php @@ -594,70 +594,99 @@ public function updateImageDataProvider(): array } /** - * Tests that images positions are inconsistent across store-views if images were added in a store-view level + * Tests that images are added correctly * * @magentoDataFixture Magento/Catalog/_files/product_with_image.php * @magentoDataFixture Magento/Store/_files/second_store.php + * @dataProvider addImagesDataProvider + * @param string $addFromStore + * @param array $newImages + * @param string $viewFromStore + * @param array $expectedImages + * @param array $select * @return void */ - public function testAddImageInStoreView(): void - { - $secondStoreId = (int)$this->storeRepository->get('fixture_second_store')->getId(); - $existingImagePath = '/m/a/magento_image.jpg'; - $newImagePath = '/m/a/magento_small_image.jpg'; - $product = $this->getProduct($secondStoreId); + public function testAddImages( + string $addFromStore, + array $newImages, + string $viewFromStore, + array $expectedImages, + array $select = ['file', 'label', 'position'] + ): void { + $storeId = (int)$this->storeRepository->get($addFromStore)->getId(); + $product = $this->getProduct($storeId); $images = $product->getData('media_gallery')['images']; - $newImage = [ - 'file' => $newImagePath, - 'position' => 2, - 'label' => 'New Image Alt Text', - 'disabled' => 0, - 'media_type' => 'image' - ]; - $images[] = $newImage; + $images = array_merge($images, $newImages); $product->setData('media_gallery', ['images' => $images]); $this->updateHandler->execute($product); - $product = $this->getProduct(Store::DEFAULT_STORE_ID); - $expectedImages = [ - [ - 'file' => $existingImagePath, - 'label' => 'Image Alt Text', - 'position' => 1 - ], - [ - 'file' => $newImagePath, - 'label' => null, - 'position' => 2 - ], - ]; + $storeId = (int)$this->storeRepository->get($viewFromStore)->getId(); + $product = $this->getProduct($storeId); $actualImages = array_map( - function (\Magento\Framework\DataObject $item) { - return $item->toArray(['file', 'label', 'position']); + function (\Magento\Framework\DataObject $item) use ($select) { + return $item->toArray($select); }, $product->getMediaGalleryImages()->getItems() ); $this->assertEquals($expectedImages, array_values($actualImages)); - $product->cleanModelCache(); - $product = $this->getProduct($secondStoreId); - $expectedImages = [ + } + + /** + * @return array[] + */ + public function addImagesDataProvider(): array + { + return [ [ - 'file' => $existingImagePath, - 'label' => 'Image Alt Text', - 'position' => 1 + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_small_image.jpg', + 'position' => 2, + 'label' => 'New Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ] + ], + 'default', + [ + [ + 'file' => '/m/a/magento_image.jpg', + 'label' => 'Image Alt Text', + 'position' => 1, + ], + [ + 'file' => '/m/a/magento_small_image.jpg', + 'label' => null, + 'position' => 2, + ], + ] ], [ - 'file' => $newImagePath, - 'label' => 'New Image Alt Text', - 'position' => 2 - ], + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_small_image.jpg', + 'position' => 2, + 'label' => 'New Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image' + ] + ], + 'fixture_second_store', + [ + [ + 'file' => '/m/a/magento_image.jpg', + 'label' => 'Image Alt Text', + 'position' => 1, + ], + [ + 'file' => '/m/a/magento_small_image.jpg', + 'label' => 'New Image Alt Text', + 'position' => 2, + ], + ] + ] ]; - $actualImages = array_map( - function (\Magento\Framework\DataObject $item) { - return $item->toArray(['file', 'label', 'position']); - }, - $product->getMediaGalleryImages()->getItems() - ); - $this->assertEquals($expectedImages, array_values($actualImages)); } /** diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 01a6bfe7b39b6..3ca6754c77767 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -3330,4 +3330,89 @@ public function testUpdateImageByNameNotPrefixedWithSlash() $imageItems = $product->getMediaGalleryImages()->getItems(); $this->assertCount(0, $imageItems); } + + /** + * Tests that images are imported correctly + * + * @magentoDataFixture mediaImportImageFixture + * @magentoDataFixture Magento/Store/_files/core_fixturestore.php + * @magentoDataFixture Magento/Catalog/_files/product_with_image.php + * @dataProvider importImagesDataProvider + * @magentoAppIsolation enabled + * @param string $importFile + * @param string $productSku + * @param string $storeCode + * @param array $expectedImages + * @param array $select + */ + public function testImportImages( + string $importFile, + string $productSku, + string $storeCode, + array $expectedImages, + array $select = ['file', 'label', 'position'] + ): void { + $this->importDataForMediaTest($importFile); + $product = $this->getProductBySku($productSku, $storeCode); + $actualImages = array_map( + function (\Magento\Framework\DataObject $item) use ($select) { + return $item->toArray($select); + }, + $product->getMediaGalleryImages()->getItems() + ); + $this->assertEquals($expectedImages, array_values($actualImages)); + } + + /** + * @return array[] + */ + public function importImagesDataProvider(): array + { + return [ + [ + 'import_media_additional_images_storeview.csv', + 'simple', + 'default', + [ + [ + 'file' => '/m/a/magento_image.jpg', + 'label' => 'Image Alt Text', + 'position' => 1 + ], + [ + 'file' => '/m/a/magento_additional_image_one.jpg', + 'label' => null, + 'position' => 2 + ], + [ + 'file' => '/m/a/magento_additional_image_two.jpg', + 'label' => null, + 'position' => 3 + ], + ] + ], + [ + 'import_media_additional_images_storeview.csv', + 'simple', + 'fixturestore', + [ + [ + 'file' => '/m/a/magento_image.jpg', + 'label' => 'Image Alt Text', + 'position' => 1 + ], + [ + 'file' => '/m/a/magento_additional_image_one.jpg', + 'label' => 'Additional Image Label One', + 'position' => 2 + ], + [ + 'file' => '/m/a/magento_additional_image_two.jpg', + 'label' => 'Additional Image Label Two', + 'position' => 3 + ], + ] + ] + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv new file mode 100644 index 0000000000000..ed8755a73fcb1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv @@ -0,0 +1,2 @@ +"sku","store_view_code","additional_images","additional_image_labels" +"simple","fixturestore","magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two" From c84b731e5be20464dab54c25a1d3ee8bc7150d35 Mon Sep 17 00:00:00 2001 From: Arnob Saha Date: Thu, 3 Dec 2020 12:57:20 -0600 Subject: [PATCH 190/346] MC-38655: [GraphQL] Gifting message is not saved in Order - Missing the event at GraphQL while Gift message saving --- .../GiftMessageGraphQl/etc/graphql/events.xml | 12 ++++++ .../GraphQl/Quote/Guest/PlaceOrderTest.php | 39 +++++++++++++++++++ .../GraphQl/Quote/_files/set_gift_options.php | 33 ++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 app/code/Magento/GiftMessageGraphQl/etc/graphql/events.xml create mode 100644 dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_gift_options.php diff --git a/app/code/Magento/GiftMessageGraphQl/etc/graphql/events.xml b/app/code/Magento/GiftMessageGraphQl/etc/graphql/events.xml new file mode 100644 index 0000000000000..2411221ded375 --- /dev/null +++ b/app/code/Magento/GiftMessageGraphQl/etc/graphql/events.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/PlaceOrderTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/PlaceOrderTest.php index 72d35fdd51b96..db9a12e654a2c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/PlaceOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/Guest/PlaceOrderTest.php @@ -327,6 +327,45 @@ public function testPlaceOrderOfCustomerCart() $this->graphQlMutation($query); } + /** + * Test place order with gift message options + * + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoConfigFixture default_store carriers/flatrate/active 1 + * @magentoConfigFixture default_store carriers/tablerate/active 1 + * @magentoConfigFixture default_store carriers/freeshipping/active 1 + * @magentoConfigFixture default_store payment/banktransfer/active 1 + * @magentoConfigFixture default_store payment/cashondelivery/active 1 + * @magentoConfigFixture default_store payment/checkmo/active 1 + * @magentoConfigFixture default_store payment/purchaseorder/active 1 + * @magentoConfigFixture sales/gift_options/allow_order 1 + * @magentoConfigFixture default_store customer/create_account/auto_group_assign 1 + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/guest/set_guest_email.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_gift_options.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_shipping_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_new_billing_address.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_flatrate_shipping_method.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/set_checkmo_payment_method.php + */ + public function testPlaceOrderWithGiftMessage() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $query = $this->getQuery($maskedQuoteId); + $response = $this->graphQlMutation($query); + + self::assertArrayHasKey('placeOrder', $response); + self::assertArrayHasKey('order_number', $response['placeOrder']['order']); + self::assertEquals($reservedOrderId, $response['placeOrder']['order']['order_number']); + $orderIncrementId = $response['placeOrder']['order']['order_number']; + $order = $this->orderFactory->create(); + $order->loadByIncrementId($orderIncrementId); + $this->assertNotEmpty($order->getGiftMessageId()); + } + /** * @param string $maskedQuoteId * @return string diff --git a/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_gift_options.php b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_gift_options.php new file mode 100644 index 0000000000000..c870fa53c5e39 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQl/Quote/_files/set_gift_options.php @@ -0,0 +1,33 @@ +get(QuoteFactory::class); +/** @var QuoteResource $quoteResource */ +$quoteResource = $objectManager->get(QuoteResource::class); +/** @var CartRepositoryInterface $cartRepository */ +$cartRepository = $objectManager->get(CartRepositoryInterface::class); + + +/** @var \Magento\GiftMessage\Model\Message $message */ +$message = $objectManager->create(\Magento\GiftMessage\Model\Message::class); +$message->setSender('Romeo'); +$message->setRecipient('Mercutio'); +$message->setMessage('I thought all for the best.'); +$message->save(); + +$quote = $quoteFactory->create(); +$quoteResource->load($quote, 'test_quote', 'reserved_order_id'); +$quote->setGiftMessageId($message->getId()); +$cartRepository->save($quote); From 51f5c43dbcf87ee1352d5ed2647479890cec3e9f Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" Date: Fri, 4 Dec 2020 10:28:06 +0200 Subject: [PATCH 191/346] MC-38973: Duplicate address by order from admin --- .../view/adminhtml/templates/order/create/form/address.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml index 80083569df889..638ac7e66f769 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/form/address.phtml @@ -125,7 +125,7 @@ endif; ?> class="admin__control-checkbox"/> + class="admin__field-label">escapeHtml(__('Add to address book')) ?> getIsShipping() ? 'shipping' : 'billing') . '-overlay'; ?> From a119cbeaedeed60b4d5b7b62c05aa756e579a330 Mon Sep 17 00:00:00 2001 From: Dmitry Furs Date: Fri, 4 Dec 2020 13:51:06 +0300 Subject: [PATCH 192/346] Invalid combination of tabs and spaces in phpstan.neon --- .../Test/Php/_files/phpstan/phpstan.neon | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/phpstan.neon b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/phpstan.neon index d487fbe602acf..0bdb5861dbf33 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/phpstan.neon +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpstan/phpstan.neon @@ -1,41 +1,41 @@ parameters: - checkExplicitMixedMissingReturn: true - checkPhpDocMissingReturn: true - reportUnmatchedIgnoredErrors: false - excludes_analyse: - - %rootDir%/../../../lib/internal/Magento/Framework/ObjectManager/Test/Unit/* - - %rootDir%/../../../*/_files/* - - %rootDir%/../../../dev/tests/*/Fixtures/* - - %rootDir%/../../../dev/tests/*/tmp/* - - %rootDir%/../../../dev/tests/*/_generated/* - - %rootDir%/../../../pub/* - autoload_directories: - - %rootDir%/../../../dev/tests/static/framework/tests/unit/testsuite/Magento - - %rootDir%/../../../dev/tests/integration/framework/tests/unit/testsuite/Magento - - %rootDir%/../../../dev/tests/api-functional/_files/Magento - autoload_files: - - %rootDir%/../../../dev/tests/static/framework/autoload.php - - %rootDir%/../../../dev/tests/integration/framework/autoload.php - - %rootDir%/../../../dev/tests/api-functional/framework/autoload.php - - %rootDir%/../../../dev/tests/setup-integration/framework/autoload.php - - %rootDir%/../../../dev/tests/static/framework/Magento/PhpStan/autoload.php - ignoreErrors: - # Ignore PHPStan\Rules\Classes\UnusedConstructorParametersRule - - '#Constructor of class [a-zA-Z0-9\\_]+ has an unused parameter#' - # Ignore setCustomErrorHandler function not found in bootstrap files - - '#Function setCustomErrorHandler not found#' - # Ignore 'return statement is missing' error when 'void' is present in return type list - - '#Method (?:.*?) should return (?:.*?)void(?:.*?) but return statement is missing.#' - # Ignore constants, defined dynamically. - - '#Constant TESTS_WEB_API_ADAPTER not found.#' - - '#Constant TESTS_BASE_URL not found.#' - - '#Constant TESTS_XDEBUG_ENABLED not found.#' - - '#Constant TESTS_XDEBUG_SESSION not found.#' - - '#Constant INTEGRATION_TESTS_DIR not found.#' - - '#Constant MAGENTO_MODULES_PATH not found.#' - - '#Constant TESTS_MODULES_PATH not found.#' - - '#Constant TESTS_INSTALLATION_DB_CONFIG_FILE not found.#' - - '#Constant T_[A-Z_]+ not found.#' + checkExplicitMixedMissingReturn: true + checkPhpDocMissingReturn: true + reportUnmatchedIgnoredErrors: false + excludes_analyse: + - %rootDir%/../../../lib/internal/Magento/Framework/ObjectManager/Test/Unit/* + - %rootDir%/../../../*/_files/* + - %rootDir%/../../../dev/tests/*/Fixtures/* + - %rootDir%/../../../dev/tests/*/tmp/* + - %rootDir%/../../../dev/tests/*/_generated/* + - %rootDir%/../../../pub/* + autoload_directories: + - %rootDir%/../../../dev/tests/static/framework/tests/unit/testsuite/Magento + - %rootDir%/../../../dev/tests/integration/framework/tests/unit/testsuite/Magento + - %rootDir%/../../../dev/tests/api-functional/_files/Magento + autoload_files: + - %rootDir%/../../../dev/tests/static/framework/autoload.php + - %rootDir%/../../../dev/tests/integration/framework/autoload.php + - %rootDir%/../../../dev/tests/api-functional/framework/autoload.php + - %rootDir%/../../../dev/tests/setup-integration/framework/autoload.php + - %rootDir%/../../../dev/tests/static/framework/Magento/PhpStan/autoload.php + ignoreErrors: + # Ignore PHPStan\Rules\Classes\UnusedConstructorParametersRule + - '#Constructor of class [a-zA-Z0-9\\_]+ has an unused parameter#' + # Ignore setCustomErrorHandler function not found in bootstrap files + - '#Function setCustomErrorHandler not found#' + # Ignore 'return statement is missing' error when 'void' is present in return type list + - '#Method (?:.*?) should return (?:.*?)void(?:.*?) but return statement is missing.#' + # Ignore constants, defined dynamically. + - '#Constant TESTS_WEB_API_ADAPTER not found.#' + - '#Constant TESTS_BASE_URL not found.#' + - '#Constant TESTS_XDEBUG_ENABLED not found.#' + - '#Constant TESTS_XDEBUG_SESSION not found.#' + - '#Constant INTEGRATION_TESTS_DIR not found.#' + - '#Constant MAGENTO_MODULES_PATH not found.#' + - '#Constant TESTS_MODULES_PATH not found.#' + - '#Constant TESTS_INSTALLATION_DB_CONFIG_FILE not found.#' + - '#Constant T_[A-Z_]+ not found.#' services: From 63810d1471499b0e3adac3b58bd9521e9eed8e58 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" Date: Fri, 4 Dec 2020 13:22:31 +0200 Subject: [PATCH 193/346] MC-38973: Duplicate address by order from admin --- app/code/Magento/Sales/i18n/en_US.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/i18n/en_US.csv b/app/code/Magento/Sales/i18n/en_US.csv index 0e65131b7c4b0..13afa0832086e 100644 --- a/app/code/Magento/Sales/i18n/en_US.csv +++ b/app/code/Magento/Sales/i18n/en_US.csv @@ -804,3 +804,4 @@ If set YES Email field will be required during Admin order creation for new Cust "Please enter a coupon code!","Please enter a coupon code!" "Reorder is not available.","Reorder is not available." "The coupon code has been removed.","The coupon code has been removed." +"Add to address book","Add to address book" From 59194579798bf462a46adbd8eefc8ba9804bdfe4 Mon Sep 17 00:00:00 2001 From: Dmitry Furs Date: Fri, 4 Dec 2020 14:27:48 +0300 Subject: [PATCH 194/346] Adjust .editorconfig to correct the automatic formatting of db_schema_whitelist.json files --- .editorconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.editorconfig b/.editorconfig index 1a9acd92fc0fc..40f57587d3497 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,3 +16,7 @@ indent_size = 2 [{composer, auth}.json] indent_size = 4 + +[db_schema_whitelist.json] +indent_size = 4 +trim_trailing_whitespace = false From b85ba435bba0bcfdfe47a136f239eeb3194ef938 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" Date: Fri, 4 Dec 2020 16:27:24 +0200 Subject: [PATCH 195/346] fix integration tests --- dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php | 1 + .../Controller/Adminhtml/Dashboard/IndexTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php index 63fcfbd061877..85bf40b342fb5 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/ConfigTest.php @@ -149,6 +149,7 @@ public function testGetAttributeWithCacheUserDefinedAttribute() $config = Bootstrap::getObjectManager()->create(\Magento\Eav\Model\Config::class); $updatedAttribute = $config->getAttribute($entityType, 'foo'); $this->assertEquals('foo', $updatedAttribute->getFrontendLabel()); + CacheCleaner::clean(['eav']); $config = Bootstrap::getObjectManager()->create(\Magento\Eav\Model\Config::class); // Check that attribute data has changed $updatedAttributeAfterCacheClean = $config->getAttribute($entityType, 'foo'); diff --git a/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php b/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php index 63c5e04bac84a..ffe2a4d6ca1c5 100644 --- a/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php +++ b/dev/tests/integration/testsuite/Magento/ReleaseNotification/Controller/Adminhtml/Dashboard/IndexTest.php @@ -34,6 +34,7 @@ protected function setUp(): void protected function tearDown(): void { $this->objectManager->removeSharedInstance(ContentProviderInterface::class); + CacheCleaner::clean(['layout']); parent::tearDown(); } From 424754fe4bc2acec733f6bc9736afde5232553c7 Mon Sep 17 00:00:00 2001 From: Anna Pak Date: Fri, 4 Dec 2020 18:27:06 +0200 Subject: [PATCH 196/346] changed naming --- ...ITest.xml => AdminMassOrdersCancelClosedAndCompleteTest.xml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/code/Magento/Sales/Test/Mftf/Test/{AdminMassOrdersCancelCompleteAndClosedAPITest.xml => AdminMassOrdersCancelClosedAndCompleteTest.xml} (98%) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml similarity index 98% rename from app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml rename to app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml index 5cb54f0fd5613..a4f4e006837e1 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedAPITest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml @@ -8,7 +8,7 @@ - + From 035442d47019e7a82bc193787adce2086032f3a5 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Fri, 4 Dec 2020 18:27:58 +0200 Subject: [PATCH 197/346] updated deprecated test --- .../Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml index 793e1a07950c9..10b3ba05aa2bb 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelCompleteAndClosedTest.xml @@ -8,7 +8,7 @@ <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AdminMassOrdersCancelCompleteAndClosedTest" deprecated="Use AdminMassOrdersCancelCompleteAndClosedAPITest instead"> + <test name="AdminMassOrdersCancelCompleteAndClosedTest" deprecated="Use AdminMassOrdersCancelClosedAndCompleteTest instead"> <annotations> <stories value="Mass Update Orders"/> <title value="DEPRECATED. Mass cancel orders in status Complete, Closed"/> @@ -18,7 +18,7 @@ <group value="sales"/> <group value="mtf_migrated"/> <skip> - <issueId value="DEPRECATED">Use AdminMassOrdersCancelCompleteAndClosedAPITest instead</issueId> + <issueId value="DEPRECATED">Use AdminMassOrdersCancelClosedAndCompleteTest instead</issueId> </skip> </annotations> <before> From db17e70f8ec0b2da5f7e9dfe6434d5b37cfcdf21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vinicius=20Bordinh=C3=A3o?= <vinicius.bordinhao@blueacornici.com> Date: Mon, 7 Dec 2020 01:08:16 -0300 Subject: [PATCH 198/346] ISSUE-29690: Developing MTFT tests covering the respective issue. --- ...ctOfConfigurableProductPageActionGroup.xml | 25 ++++ ...roductWithVideoAssociatedToVariantTest.xml | 134 ++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontSelectSimpleProductOfConfigurableProductPageActionGroup.xml create mode 100644 app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontSelectSimpleProductOfConfigurableProductPageActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontSelectSimpleProductOfConfigurableProductPageActionGroup.xml new file mode 100644 index 0000000000000..bfbef80f026da --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/StorefrontSelectSimpleProductOfConfigurableProductPageActionGroup.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontSelectSimpleProductOfConfigurableProductPageActionGroup"> + <annotations> + <description>Goes to the provided Storefront URL. Selects the provided Product Option under the Product Attribute.</description> + </annotations> + <arguments> + <argument name="urlKey" type="string"/> + <argument name="productAttribute" type="string"/> + <argument name="productOption" type="string"/> + </arguments> + + <amOnPage url="{{urlKey}}.html" stepKey="goToStorefrontPage"/> + <waitForPageLoad stepKey="waitForProductFrontPageToLoad"/> + <selectOption selector="{{StorefrontProductInfoMainSection.productOptionSelect(productAttribute)}}" userInput="{{productOption}}" stepKey="selectOption1"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml new file mode 100644 index 0000000000000..7963eecbe5224 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml @@ -0,0 +1,134 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCreateConfigurableProductWithVideoAssociatedToVariantTest"> + <annotations> + <features value="ConfigurableProduct"/> + <stories value="Add videos for all variant product"/> + <title value="Admin should be able to add videos for a variant Product"/> + <description value="Admin should be able to add videos for a Variant Product"/> + <severity value="MAJOR"/> + <testCaseId value="MC-37344"/> + <group value="ConfigurableProduct"/> + </annotations> + + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <createData entity="SimpleSubCategory" stepKey="categoryHandle"/> + + <createData entity="SimpleProduct" stepKey="simple1Handle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + + <createData entity="SimpleProduct" stepKey="simple2Handle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + + <createData entity="BaseConfigurableProduct" stepKey="baseConfigProductHandle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + <createData entity="productDropDownAttribute" stepKey="productAttributeHandle"/> + + <createData entity="productAttributeOption1" stepKey="productAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + <createData entity="productAttributeOption2" stepKey="productAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <createData entity="AddToDefaultSet" stepKey="addToAttributeSetHandle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + + <createData entity="SimpleOne" stepKey="childProductHandle1"> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption1Handle"/> + </createData> + <createData entity="SimpleOne" stepKey="childProductHandle2"> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption2Handle"/> + </createData> + + <createData entity="ConfigurableProductTwoOptions" stepKey="configProductOptionHandle"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption1Handle"/> + <requiredEntity createDataKey="getAttributeOption2Handle"/> + </createData> + + <createData entity="ConfigurableProductAddChild" stepKey="configProductHandle1"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="childProductHandle1"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="configProductHandle2"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="childProductHandle2"/> + </createData> + </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="simple1Handle" stepKey="deleteSimple1"/> + <deleteData createDataKey="simple2Handle" stepKey="deleteSimple2"/> + <deleteData createDataKey="childProductHandle1" stepKey="deleteChild1"/> + <deleteData createDataKey="childProductHandle2" stepKey="deleteChild2"/> + <deleteData createDataKey="baseConfigProductHandle" stepKey="deleteConfig"/> + <deleteData createDataKey="categoryHandle" stepKey="deleteCategory"/> + <deleteData createDataKey="productAttributeHandle" stepKey="deleteProductAttribute"/> + + <!-- Reindex invalidated indices after product attribute has been created/deleted --> + <magentoCron groups="index" stepKey="reindexInvalidatedIndices"/> + </after> + + <actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="productIndexPage"/> + + <actionGroup ref="FilterProductGridBySkuActionGroup" stepKey="filterProductGrid"> + <argument name="product" value="$$childProductHandle1$$"/> + </actionGroup> + <actionGroup ref="OpenProductForEditByClickingRowXColumnYInProductGridActionGroup" stepKey="openProducForEditByClickingRow1Column2InProductGrid1"/> + + <actionGroup ref="AddProductVideoActionGroup" stepKey="addVideoForProduct" /> + + <!-- Add image to product --> + <actionGroup ref="AddProductImageActionGroup" stepKey="addImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct"/> + + <!-- Assert product image in admin product form --> + <actionGroup ref="AssertProductImageAdminProductPageActionGroup" stepKey="assertProductImageAdminProductPage"/> + + <!-- Assert product in storefront product page --> + <actionGroup ref="AssertProductNameAndSkuInStorefrontProductPageByCustomAttributeUrlKeyActionGroup" stepKey="AssertProductInStorefrontProductPage"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + </actionGroup> + + <actionGroup ref="StorefrontSelectSimpleProductOfConfigurableProductPageActionGroup" stepKey="assertSimpleProductIsAccessibleInStorefrontProductPageActionGroup" > + <argument name="urlKey" value="$$baseConfigProductHandle.custom_attributes[url_key]$$" /> + <argument name="productAttribute" value="$$productAttributeHandle.default_value$$"/> + <argument name="productOption" value="$$getAttributeOption1Handle.value$$"/> + </actionGroup> + + <!-- Assert product image in storefront product page --> + <actionGroup ref="AssertProductImageStorefrontProductPage2ActionGroup" stepKey="assertProductImageStorefrontProductPageActionGroup"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + + <!-- Assert product video in storefront product page --> + <actionGroup ref="AssertProductVideoStorefrontProductPageActionGroup" stepKey="assertProductVideoStorefrontProductPage"/> + </test> +</tests> From 01451f5bd1b2fdc403bed1c382c8dd3fd3879ee3 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Mon, 7 Dec 2020 10:58:20 +0200 Subject: [PATCH 199/346] MC-35717: Admin can not add a Product with a Customizable Option (File) to Order by SKU --- .../catalog/product/composite/configure.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js index fcb193b9565ef..4040ff9d684f4 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/product/composite/configure.js @@ -617,12 +617,14 @@ define([ * @param blockItem */ var _renameFields = function (method, blockItem, listType) { - var pattern = null; - var patternFlat = null; - var replacement = null; - var replacementFlat = null; - var scopeArr = blockItem.id.match(/.*\[\w+\]\[([^\]]+)\]$/); - var itemId = scopeArr[1]; + var pattern = null; + var patternFlat = null; + var patternPrefix = RegExp('\\s', 'g'); + var replacement = null; + var replacementFlat = null; + var replacementPrefix = '_'; + var scopeArr = blockItem.id.match(/.*\[\w+\]\[([^\]]+)\]$/); + var itemId = scopeArr[1]; if (method == 'current_confirmed_to_form') { pattern = RegExp('(\\w+)(\\[?)'); @@ -652,12 +654,15 @@ define([ var rename = function (elms) { for (var i = 0; i < elms.length; i++) { if (elms[i].name && elms[i].type == 'file') { - elms[i].name = elms[i].name.replace(patternFlat, replacementFlat); + var prefixName = 'options[files_prefix]', + prefixValue = 'item_' + itemId + '_'; + self.blockFormFields.insert(new Element('input', { type: 'hidden', - name: 'options[files_prefix]'.replace(pattern, replacement), - value: 'item_' + itemId + '_' + name: prefixName.replace(pattern, replacement), + value: prefixValue.replace(patternPrefix, replacementPrefix) })); + elms[i].name = elms[i].name.replace(patternFlat, replacementFlat); } else if (elms[i].name) { elms[i].name = elms[i].name.replace(pattern, replacement); } From beb05984b2798ffdb262bac8c65174a5f89355ad Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Mon, 7 Dec 2020 11:10:56 +0200 Subject: [PATCH 200/346] MC-38973: Duplicate address by order from admin --- .../Test/Mftf/Test/AdminSaveInAddressBookCheckboxStateTest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminSaveInAddressBookCheckboxStateTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminSaveInAddressBookCheckboxStateTest.xml index ac0af3f5b80db..f8136a9071a1a 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminSaveInAddressBookCheckboxStateTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminSaveInAddressBookCheckboxStateTest.xml @@ -47,6 +47,8 @@ <actionGroup ref="AddSimpleProductToOrderActionGroup" stepKey="addSimpleProductToOrder"> <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> + <!-- By default checkbox 'Add to address book' must be unchecked --> + <dontSeeCheckboxIsChecked selector="{{AdminOrderFormBillingAddressSection.SaveAddress}}" stepKey="checkBoxAddBillingAddressIsUnchecked"/> <!-- Just in case uncheck and check 'Same as Billing Address checkbox' --> <comment userInput="Just in case uncheck and check 'Same as Billing Address checkbox'" stepKey="uncheckAndCheckAgain"/> <uncheckOption selector="{{AdminOrderFormShippingAddressSection.SameAsBilling}}" stepKey="unCheckSameAsShippingAddressCheckbox"/> From f65490bb49a827eaf345173f16dbfd93371fb554 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Mon, 7 Dec 2020 11:45:08 +0200 Subject: [PATCH 201/346] MC-36779: Product still present in the Wish List after added to order --- .../Test/CreateOrderFromEditCustomerPageTest.xml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml index 89a5fe07ced6a..e4feb033cd610 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml @@ -139,15 +139,13 @@ <!-- Move products to order from Wish List --> <waitForElementVisible selector="{{AdminCreateOrderWishListSection.addProductToOrderCheckBox($$simpleProduct.name$$)}}" stepKey="waitForCheckBoxToVisible"/> <click selector="{{AdminCreateOrderWishListSection.addProductToOrderCheckBox($$simpleProduct.name$$)}}" stepKey="selectProductToAddToOrder"/> - <click selector="{{AdminCustomerCreateNewOrderSection.updateChangesBtn}}" stepKey="clickOnUpdateButton"/> + <click selector="{{AdminCustomerCreateNewOrderSection.updateChangesBtn}}" stepKey="clickUpdateChangesButton"/> <click selector="{{AdminCreateOrderWishListSection.addConfigProductToOrder($$createConfigProduct.name$$)}}" stepKey="AddConfigurableProductToOrder"/> <waitForElementVisible selector="{{AdminOrderFormConfigureProductSection.optionSelect($$createConfigProductAttribute.default_frontend_label$$)}}" stepKey="waitForConfigurablePopover"/> <selectOption selector="{{AdminOrderFormConfigureProductSection.optionSelect($$createConfigProductAttribute.default_frontend_label$$)}}" userInput="$$getConfigAttributeOption1.label$$" stepKey="selectConfigurableOption"/> <click selector="{{AdminOrderFormConfigureProductSection.ok}}" stepKey="clickOkButton"/> - - <!-- After move, assert products are NOT present in Wish List section --> - <dontSee selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$simpleProduct.name$" stepKey="dontSeeSimpleProductInWishList"/> - <dontSee selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$createConfigProduct.name$" stepKey="dontSeeConfigurableProductInWishList"/> + <comment userInput="Click OK button to update lists" stepKey="clickOnUpdateButton"/> + <waitForPageLoad stepKey="waitForAdminOrderItemsOrderedSectionPageLoad1"/> <!-- Assert Products in Order item section --> <see selector="{{AdminOrderItemsOrderedSection.productName}}" userInput="$$simpleProduct.name$$" stepKey="seeSimpleProductInOrderItemGrid"/> @@ -174,6 +172,10 @@ <dontSee selector="{{AdminCreateOrderShoppingCartSection.shoppingCartBlock}}" userInput="$$simpleProduct.name$$" stepKey="donSeeProductInShoppingCart"/> <dontSee selector="{{AdminCreateOrderShoppingCartSection.shoppingCartBlock}}" userInput="$$simpleProduct1.name$$" stepKey="dontSeeSecondProductInShoppingCart"/> + <!-- After move, assert products are not present in Wish List section --> + <dontSee selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$$simpleProduct.name$$" stepKey="seeSimpleProductInWishList1"/> + <dontSee selector="{{AdminCreateOrderWishListSection.wishListBlock}}" userInput="$$createConfigProduct.name$$" stepKey="seeConfigurableProductInWishList1"/> + <!-- After move, assert products are present in order items section --> <see selector="{{AdminOrderItemsOrderedSection.productName}}" userInput="$$simpleProduct.name$$" stepKey="seeSimpleProductInOrderItemGrid1"/> <see selector="{{AdminOrderItemsOrderedSection.productName}}" userInput="$$createConfigProduct.name$$" stepKey="seeConfigProductInOrderItemGrid1"/> From edbb92b3e8e72c76e537a1d490fc870630eb2bb3 Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Mon, 7 Dec 2020 12:10:22 +0200 Subject: [PATCH 202/346] MC-39128: Cannot delete second layout update in widget --- app/code/Magento/Backend/Block/Widget/Button.php | 5 ++++- .../Backend/Test/Unit/Block/Widget/ButtonTest.php | 12 ++++++++++++ .../Widget/Instance/Edit/Tab/Main/Layout.php | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Backend/Block/Widget/Button.php b/app/code/Magento/Backend/Block/Widget/Button.php index 3b5eca6a61779..cb8269f692f02 100644 --- a/app/code/Magento/Backend/Block/Widget/Button.php +++ b/app/code/Magento/Backend/Block/Widget/Button.php @@ -5,9 +5,9 @@ */ namespace Magento\Backend\Block\Widget; +use Magento\Backend\Block\Template\Context; use Magento\Framework\App\ObjectManager; use Magento\Framework\Math\Random; -use Magento\Backend\Block\Template\Context; use Magento\Framework\View\Helper\SecureHtmlRenderer; /** @@ -125,6 +125,9 @@ protected function _prepareAttributes($title, $classes, $disabled) 'value' => $this->getValue(), 'disabled' => $disabled, ]; + if ($this->hasData('onclick_attribute')) { + $attributes['onclick'] = $this->getData('onclick_attribute'); + } if ($this->hasData('backend_button_widget_hook_id')) { $attributes['backend-button-widget-hook-id'] = $this->getData('backend_button_widget_hook_id'); } diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/ButtonTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/ButtonTest.php index be14a51ffb27b..33667f158b9d9 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/ButtonTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/ButtonTest.php @@ -94,4 +94,16 @@ public function getAttributesHtmlDataProvider() ] ]; } + + /** + * Verifies ability of adding button onclick attribute + * + * @return void + */ + public function testOnClickAttribute(): void + { + $this->_blockMock->setData(['onclick_attribute' => 'value']); + $attributes = $this->_blockMock->getAttributesHtml(); + $this->assertStringContainsString('onclick', $attributes); + } } diff --git a/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php b/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php index c48bf9e7e4c7a..1d8d1ec37494b 100644 --- a/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php +++ b/app/code/Magento/Widget/Block/Adminhtml/Widget/Instance/Edit/Tab/Main/Layout.php @@ -327,7 +327,7 @@ public function getRemoveLayoutButtonHtml() )->setData( [ 'label' => $this->escapeHtmlAttr(__('Remove Layout Update')), - 'onclick' => 'WidgetInstance.removePageGroup(this)', + 'onclick_attribute' => 'WidgetInstance.removePageGroup(this)', 'class' => 'action-delete', ] ); From 32b93deca198a62fc4e2e67012d63ad457c43728 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Mon, 7 Dec 2020 13:30:04 +0200 Subject: [PATCH 203/346] fix graphql test --- .../Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index 2f6fc2ee112fa..c87daafa66728 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -223,11 +223,10 @@ public function testRedirectsAndCustomInput() $urlRewriteModel->setRedirectType('301'); $urlRewriteModel->setId($urlRewriteModel->getId()); $urlRewriteModel->save(); - ObjectManager::getInstance()->get(\Magento\TestFramework\Helper\CacheCleaner::class)->clean(['eav']); //modifying query by adding spaces to avoid getting cached values. $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), - $customUrl, + $customUrl . ' ', $actualUrls->getRequestPath(), strtoupper($actualUrls->getEntityType()), 301 From a4403e9006d1bb4a4c75baa71915b7df12e3c7e8 Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Mon, 7 Dec 2020 13:55:42 +0200 Subject: [PATCH 204/346] Rename AdminCheckProductQtyAfterOrderCancelling.xml to AdminCheckProductQtyAfterOrderCancellingTest.xml --- ...lling.xml => AdminCheckProductQtyAfterOrderCancellingTest.xml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/code/Magento/ConfigurableProduct/Test/Mftf/Test/{AdminCheckProductQtyAfterOrderCancelling.xml => AdminCheckProductQtyAfterOrderCancellingTest.xml} (100%) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancellingTest.xml similarity index 100% rename from app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancelling.xml rename to app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCheckProductQtyAfterOrderCancellingTest.xml From 2f8b94d171dbb8c0847ffe7e6b3b013431c233c3 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Mon, 7 Dec 2020 14:03:15 +0200 Subject: [PATCH 205/346] MC-39521: Random deadlocks during setting email sent flag --- app/code/Magento/Sales/Model/EmailSenderHandler.php | 5 +++-- .../Magento/Sales/Test/Unit/Model/EmailSenderHandlerTest.php | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Model/EmailSenderHandler.php b/app/code/Magento/Sales/Model/EmailSenderHandler.php index a201c1285ae49..3a7a5727d8341 100644 --- a/app/code/Magento/Sales/Model/EmailSenderHandler.php +++ b/app/code/Magento/Sales/Model/EmailSenderHandler.php @@ -132,8 +132,9 @@ public function sendEmails() /** @var \Magento\Sales\Model\AbstractModel $item */ foreach ($entityCollection->getItems() as $item) { if ($this->emailSender->send($item, true)) { - $this->entityResource->save( - $item->setEmailSent(true) + $this->entityResource->saveAttribute( + $item->setEmailSent(true), + 'email_sent' ); } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/EmailSenderHandlerTest.php b/app/code/Magento/Sales/Test/Unit/Model/EmailSenderHandlerTest.php index 757a026aa5d68..2a7b44efa5261 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/EmailSenderHandlerTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/EmailSenderHandlerTest.php @@ -100,7 +100,7 @@ protected function setUp(): void false, false, true, - ['save'] + ['saveAttribute'] ); $this->entityCollection = $this->getMockForAbstractClass( @@ -252,7 +252,7 @@ public function testExecute($configValue, $collectionItems, $emailSendingResult) $this->entityResource ->expects($this->once()) - ->method('save') + ->method('saveAttribute') ->with($collectionItem); } } From 8f40a2b8ee2e0e091573ea84c496be5808b495b7 Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Sat, 5 Dec 2020 07:59:57 -0600 Subject: [PATCH 206/346] MC-39034: GraphQL shows incorrect grand total on the Billing Step - Adding test and empty checking of shipping amount --- .../Magento/SalesRule/Model/Validator.php | 2 +- .../Test/Unit/Model/ValidatorTest.php | 83 ++++++++++++++++++- 2 files changed, 83 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Validator.php b/app/code/Magento/SalesRule/Model/Validator.php index cc0333480f7b0..7b3a6b15b7a32 100644 --- a/app/code/Magento/SalesRule/Model/Validator.php +++ b/app/code/Magento/SalesRule/Model/Validator.php @@ -318,7 +318,7 @@ public function process(AbstractItem $item) public function processShippingAmount(Address $address) { $shippingAmount = $address->getShippingAmountForDiscount(); - if ($shippingAmount !== null) { + if (!empty($shippingAmount)) { $baseShippingAmount = $address->getBaseShippingAmountForDiscount(); } else { $shippingAmount = $address->getShippingAmount(); diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/ValidatorTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/ValidatorTest.php index 4224cfafb3c8c..c895802153f45 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/ValidatorTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/ValidatorTest.php @@ -33,6 +33,7 @@ use Magento\Store\Model\Store; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Zend_Db_Select_Exception; /** * Test sales rule model validator @@ -538,7 +539,7 @@ public function testProcessShippingAmountProcessDisabled() * @param int $ruleDiscount * @param int $shippingDiscount * @dataProvider dataProviderActions - * @throws \Zend_Db_Select_Exception + * @throws Zend_Db_Select_Exception */ public function testProcessShippingAmountActions($action, $ruleDiscount, $shippingDiscount): void { @@ -595,6 +596,86 @@ public static function dataProviderActions() ]; } + /** + * Tests shipping amount with full discount action. + * + * @dataProvider dataProviderForFullShippingDiscount + * @param string $action + * @param float $ruleDiscount + * @param float $shippingDiscount + * @param float $shippingAmount + * @param float $quoteBaseSubTotal + * @throws Zend_Db_Select_Exception + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testProcessShippingAmountWithFullFixedPercentDiscount( + string $action, + float $ruleDiscount, + float $shippingDiscount, + float $shippingAmount, + float $quoteBaseSubTotal + ): void { + $ruleMock = $this->getMockBuilder(Rule::class) + ->disableOriginalConstructor() + ->setMethods(['getApplyToShipping', 'getSimpleAction', 'getDiscountAmount']) + ->getMock(); + $ruleMock->method('getApplyToShipping') + ->willReturn(true); + $ruleMock->method('getDiscountAmount') + ->willReturn($ruleDiscount); + $ruleMock->method('getSimpleAction') + ->willReturn($action); + + $iterator = new \ArrayIterator([$ruleMock]); + $this->ruleCollection->method('getIterator') + ->willReturn($iterator); + + $this->utility->method('canProcessRule') + ->willReturn(true); + + $this->priceCurrency->method('convert') + ->willReturn($ruleDiscount); + + $this->priceCurrency->method('roundPrice') + ->willReturn(round($shippingDiscount, 2)); + + $this->model->init( + $this->model->getWebsiteId(), + $this->model->getCustomerGroupId(), + $this->model->getCouponCode() + ); + + $addressMock = $this->setupAddressMock($shippingAmount, $quoteBaseSubTotal); + + self::assertInstanceOf(Validator::class, $this->model->processShippingAmount($addressMock)); + self::assertEquals($shippingDiscount, $addressMock->getShippingDiscountAmount()); + } + + /** + * Get data provider array for full shipping discount action + * + * @return array + */ + public function dataProviderForFullShippingDiscount(): array + { + return [ + 'verify shipping discount when shipping amount is greater than zero' => [ + Rule::BY_PERCENT_ACTION, + 100.00, + 5.0, + 5.0, + 10.0 + ], + 'verify shipping discount when shipping amount is zero' => [ + Rule::BY_PERCENT_ACTION, + 100.00, + 5.0, + 0, + 10.0 + ] + ]; + } + /** * @param float $shippingAmount * @param float $quoteBaseSubTotal From 0d1c10836b6b8e5cce7ad2706845db2098387f5b Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Tue, 8 Dec 2020 02:46:29 +0200 Subject: [PATCH 207/346] Fix unit test subscription --- .../Mview/Test/Unit/View/SubscriptionTest.php | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php b/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php index 3142356d44084..3f3c326beb5a5 100644 --- a/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php +++ b/lib/internal/Magento/Framework/Mview/Test/Unit/View/SubscriptionTest.php @@ -49,6 +49,16 @@ class SubscriptionTest extends TestCase /** @var string */ private $tableName; + /** + * @var Config|MockObject + */ + private $mviewConfig; + + /** + * @var DefaultProcessor|MockObject + */ + private $defaultProcessor; + protected function setUp(): void { $this->tableName = 'test_table'; @@ -59,17 +69,14 @@ protected function setUp(): void ->method('quoteIdentifier') ->willReturnArgument(0); - $this->connectionMock->expects($this->any()) - ->method('describeTable') - ->willReturn([]); - + $this->defaultProcessor = $this->createMock(DefaultProcessor::class); $this->resourceMock->expects($this->atLeastOnce()) ->method('getConnection') ->willReturn($this->connectionMock); ObjectManager::getInstance()->expects($this->any()) ->method('get') ->with(DefaultProcessor::class) - ->willReturn(2); + ->willReturn($this->defaultProcessor); $this->triggerFactoryMock = $this->createMock(TriggerFactory::class); $this->viewCollectionMock = $this->getMockForAbstractClass( CollectionInterface::class, @@ -114,6 +121,7 @@ protected function setUp(): void $this->tableName, 'columnName', [], + [], $mviewConfigMock ); } @@ -367,12 +375,24 @@ public function testBuildStatementIgnoredColumnSubscriptionLevel(): void ] ] ]; + $mviewConfigMock = $this->createMock(Config::class); + $mviewConfigMock->expects($this->any()) + ->method('getView') + ->willReturn([ + 'subscriptions' => [ + $tableName => [ + 'processor' => DefaultProcessor::class + ] + ] + ]); - $this->connectionMock->expects($this->once()) + $this->connectionMock->expects($this->any()) ->method('isTableExists') + ->with('cataloginventory_stock_item') ->willReturn(true); - $this->connectionMock->expects($this->once()) + $this->connectionMock->expects($this->any()) ->method('describeTable') + ->with($tableName) ->willReturn([ 'item_id' => ['COLUMN_NAME' => 'item_id'], 'product_id' => ['COLUMN_NAME' => 'product_id'], @@ -383,10 +403,14 @@ public function testBuildStatementIgnoredColumnSubscriptionLevel(): void ]); $otherChangelogMock = $this->getMockForAbstractClass(ChangelogInterface::class); - $otherChangelogMock->expects($this->once()) + $otherChangelogMock->expects($this->any()) ->method('getViewId') ->willReturn($viewId); + $otherChangelogMock->expects($this->once()) + ->method('getColumnName') + ->willReturn('entity_id'); + $model = new Subscription( $this->resourceMock, $this->triggerFactoryMock, @@ -395,7 +419,8 @@ public function testBuildStatementIgnoredColumnSubscriptionLevel(): void $tableName, 'columnName', [], - $ignoredData + $ignoredData, + $mviewConfigMock ); $method = new \ReflectionMethod($model, 'buildStatement'); From 958582ee34a6734f101074d64680ad57f9f70f50 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Tue, 8 Dec 2020 12:20:49 +0200 Subject: [PATCH 208/346] add mftf --- ...tProductOnGroupedOptionGridActionGroup.xml | 31 +++++++++++++ .../AdminGroupedProductOptionGridSection.xml | 15 +++++++ ...oupedProductNonDefaultAttributeSetTest.xml | 45 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminAssertProductOnGroupedOptionGridActionGroup.xml create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminGroupedProductOptionGridSection.xml create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminAssertProductOnGroupedOptionGridActionGroup.xml b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminAssertProductOnGroupedOptionGridActionGroup.xml new file mode 100644 index 0000000000000..2f706f45f834d --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminAssertProductOnGroupedOptionGridActionGroup.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAssertProductOnGroupedOptionGridActionGroup"> + <annotations> + <description>Admin assert product on grouped option grid.</description> + </annotations> + <arguments> + <argument name="product"/> + </arguments> + + <grabTextFrom selector="{{AdminGroupedProductOptionGridSection.productName}}" stepKey="grabProductName"/> + <assertEquals stepKey="assertProductName"> + <expectedResult type="string">{{product.name}}</expectedResult> + <actualResult type="variable">$grabProductName</actualResult> + </assertEquals> + + <grabTextFrom selector="{{AdminGroupedProductOptionGridSection.productSku}}" stepKey="grabProductSku"/> + <assertEquals stepKey="assertProductSku"> + <expectedResult type="string">{{product.sku}}</expectedResult> + <actualResult type="variable">$grabProductSku</actualResult> + </assertEquals> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminGroupedProductOptionGridSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminGroupedProductOptionGridSection.xml new file mode 100644 index 0000000000000..1fff52c1d30cd --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminGroupedProductOptionGridSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminGroupedProductOptionGridSection"> + <element name="productName" type="text" selector=".data-row td[data-index='name']"/> + <element name="productSku" type="text" selector=".data-row td[data-index='sku']"/> + </section> +</sections> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml new file mode 100644 index 0000000000000..44ea267c7b5d4 --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCreateGroupedProductNonDefaultAttributeSetTest"> + <annotations> + <features value="GroupedProduct"/> + <stories value="Create product"/> + <title value="Create Grouped Product when non-default attribute set is chosen"/> + <description value="Create Grouped Product with simple when non-default attribute set is chosen"/> + <group value="groupedProduct"/> + </annotations> + <before> + <createData entity="ApiProductWithDescription" stepKey="createSimpleProduct"/> + <createData entity="CatalogAttributeSet" stepKey="createAttributeSet"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteFirstProduct"/> + <deleteData createDataKey="createAttributeSet" stepKey="deleteAttributeSet"/> + </after> + + <actionGroup ref="GoToSpecifiedCreateProductPageActionGroup" stepKey="createGroupedProduct"> + <argument name="productType" value="grouped"/> + </actionGroup> + <actionGroup ref="AdminProductPageSelectAttributeSetActionGroup" stepKey="selectAttributeSet"> + <argument name="attributeSetName" value="$createAttributeSet.attribute_set_name$"/> + </actionGroup> + <actionGroup ref="FillGroupedProductFormActionGroup" stepKey="fillProductForm"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <actionGroup ref="AdminAssignProductToGroupActionGroup" stepKey="addSimpleToGroup"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="AdminAssertProductOnGroupedOptionGridActionGroup" stepKey="assertProductOptionGrid"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + </test> +</tests> From 4bdc98ef49516d2a89dc7ff61df4bcee200007a5 Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Tue, 8 Dec 2020 13:04:41 +0200 Subject: [PATCH 209/346] add severity --- .../Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml index 44ea267c7b5d4..95607a83dd26f 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml @@ -13,6 +13,7 @@ <stories value="Create product"/> <title value="Create Grouped Product when non-default attribute set is chosen"/> <description value="Create Grouped Product with simple when non-default attribute set is chosen"/> + <severity value="MAJOR"/> <group value="groupedProduct"/> </annotations> <before> From 44809b951e2a96161de14132fd899098e2746e63 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Tue, 8 Dec 2020 14:01:02 +0200 Subject: [PATCH 210/346] MC-36779: Product still present in the Wish List after added to order --- .../Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml | 2 +- .../Sales/view/adminhtml/web/order/create/scripts.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml index e4feb033cd610..08d5776b79ea0 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreateOrderFromEditCustomerPageTest.xml @@ -144,7 +144,7 @@ <waitForElementVisible selector="{{AdminOrderFormConfigureProductSection.optionSelect($$createConfigProductAttribute.default_frontend_label$$)}}" stepKey="waitForConfigurablePopover"/> <selectOption selector="{{AdminOrderFormConfigureProductSection.optionSelect($$createConfigProductAttribute.default_frontend_label$$)}}" userInput="$$getConfigAttributeOption1.label$$" stepKey="selectConfigurableOption"/> <click selector="{{AdminOrderFormConfigureProductSection.ok}}" stepKey="clickOkButton"/> - <comment userInput="Click OK button to update lists" stepKey="clickOnUpdateButton"/> + <comment userInput="Action should be removed but replaced with comment due to backward compatibility" stepKey="clickOnUpdateButton"/> <waitForPageLoad stepKey="waitForAdminOrderItemsOrderedSectionPageLoad1"/> <!-- Assert Products in Order item section --> 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 f90ad563331e6..9454fe17fe2d2 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 @@ -964,17 +964,17 @@ define([ }.bind(this)); // response handler productConfigure.setOnLoadIFrameCallback(listType, function (response) { - var area = ['items', 'shipping_method', 'billing_method', 'totals', 'giftmessage']; + var areas = ['items', 'shipping_method', 'billing_method', 'totals', 'giftmessage']; if (!response.ok) { return; } if (isWishlist) { this.removeSidebarItem(itemId, 'wishlist').done(function () { - this.loadArea(area, true); + this.loadArea(areas, true); }.bind(this)); } else { - this.loadArea(area, true); + this.loadArea(areas, true); } }.bind(this)); // show item configuration From 513bb0b5ca9c107a260d7c276b01aa26a28a25b8 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Mon, 7 Dec 2020 15:09:48 -0600 Subject: [PATCH 211/346] MC-39569: Indexers invalidated when removing products from a category - Remove catalog_category_change_products observer that invalidates category product indexer --- .../Observer/CategoryProductIndexer.php | 16 ++- .../Model/Indexer/Category/ProductTest.php | 30 ---- .../Model/ResourceModel/CategoryTest.php | 136 ++++++++++++++++++ .../catalog_category_product_reindex_all.php | 16 +++ .../catalog_product_category_reindex_all.php | 16 +++ ...alog_product_reindex_schedule_rollback.php | 12 +- 6 files changed, 190 insertions(+), 36 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_category_product_reindex_all.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_product_category_reindex_all.php diff --git a/app/code/Magento/Catalog/Observer/CategoryProductIndexer.php b/app/code/Magento/Catalog/Observer/CategoryProductIndexer.php index ca87efaa87490..bdee84762cac2 100644 --- a/app/code/Magento/Catalog/Observer/CategoryProductIndexer.php +++ b/app/code/Magento/Catalog/Observer/CategoryProductIndexer.php @@ -8,6 +8,7 @@ namespace Magento\Catalog\Observer; use Magento\Catalog\Model\Indexer\Category\Product\Processor; +use Magento\Catalog\Model\Indexer\Category\Flat\State as FlatState; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; @@ -21,12 +22,21 @@ class CategoryProductIndexer implements ObserverInterface */ private $processor; + /** + * @var FlatState + */ + private $flatState; + /** * @param Processor $processor + * @param FlatState $flatState */ - public function __construct(Processor $processor) - { + public function __construct( + Processor $processor, + FlatState $flatState + ) { $this->processor = $processor; + $this->flatState = $flatState; } /** @@ -35,7 +45,7 @@ public function __construct(Processor $processor) public function execute(Observer $observer): void { $productIds = $observer->getEvent()->getProductIds(); - if (!empty($productIds) && $this->processor->isIndexerScheduled()) { + if (!empty($productIds) && $this->processor->isIndexerScheduled() && $this->flatState->isFlatEnabled()) { $this->processor->markIndexerAsInvalid(); } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php index 8e11efa8790cf..5cfa07cf5d402 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Category/ProductTest.php @@ -245,36 +245,6 @@ public function testCatalogCategoryProductIndexInvalidateAfterDelete(): void $this->assertEquals(StateInterface::STATUS_INVALID, $status); } - /** - * Test invalidate reindex after change product position on category - * - * @magentoAppArea adminhtml - * @magentoDataFixture Magento/Catalog/_files/category_with_different_price_products.php - * - * @return void - */ - public function testCatalogCategoryProductIndexInvalidateAfterChangeProductPosition(): void - { - $this->indexer->setScheduled(true); - $indexerShouldBeValid = $this->indexer->isValid(); - - $category = $this->getCategoryByName->execute('Category 999'); - - $category->setPostedProducts([ - $this->productResource->getIdBySku('simple1000') => 1, - $this->productResource->getIdBySku('simple1001') => 2 - ]); - - $this->categoryResource->save($category); - - $state = $this->indexer->getState(); - $state->loadByIndexer($this->indexer->getId()); - $status = $state->getStatus(); - - $this->assertTrue($indexerShouldBeValid); - $this->assertEquals(StateInterface::STATUS_INVALID, $status); - } - /** * @param int $count * @return Category[] diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/CategoryTest.php index c57e981f772de..66e117a61ed2c 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/CategoryTest.php @@ -10,14 +10,21 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Model\Category as CategoryModel; +use Magento\Catalog\Model\Indexer\Category\Product as CategoryProductIndexer; +use Magento\Catalog\Model\Indexer\Product\Category as ProductCategoryIndexer; use Magento\Catalog\Model\ResourceModel\Category as CategoryResource; use Magento\Catalog\Model\ResourceModel\Category\Collection as CategoryCollection; use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory; +use Magento\Catalog\Model\ResourceModel\Product as ProductResource; +use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\Framework\Indexer\IndexerInterface; +use Magento\Framework\Indexer\IndexerRegistry; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\UrlInterface; +use Magento\Indexer\Cron\UpdateMview; use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; @@ -26,6 +33,7 @@ * Tests category resource model * * @see \Magento\Catalog\Model\ResourceModel\Category + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CategoryTest extends TestCase { @@ -54,6 +62,11 @@ class CategoryTest extends TestCase /** @var WriteInterface */ private $mediaDirectory; + /** + * @var ProductResource + */ + private $productResource; + /** * @inheritdoc */ @@ -68,6 +81,7 @@ protected function setUp(): void $this->categoryCollection = $this->objectManager->get(CategoryCollectionFactory::class)->create(); $this->filesystem = $this->objectManager->get(Filesystem::class); $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->productResource = Bootstrap::getObjectManager()->get(ProductResource::class); } /** @@ -116,6 +130,128 @@ public function testAddImageForCategory(): void $this->assertFileExists($this->mediaDirectory->getAbsolutePath($imageRelativePath)); } + /** + * Test that adding or removing products in a category should not trigger full reindex in scheduled update mode + * + * @magentoAppArea adminhtml + * @magentoAppIsolation enabled + * @magentoDbIsolation disabled + * @magentoDataFixture Magento/Catalog/_files/category_with_three_products.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_duplicated.php + * @magentoDataFixture Magento/Catalog/_files/catalog_category_product_reindex_all.php + * @magentoDataFixture Magento/Catalog/_files/catalog_product_category_reindex_all.php + * @magentoDataFixture Magento/Catalog/_files/enable_catalog_product_reindex_schedule.php + * @dataProvider catalogProductChangesWithScheduledUpdateDataProvider + * @param array $products + * @return void + */ + public function testCatalogProductChangesWithScheduledUpdate(array $products): void + { + // products are ordered by entity_id DESC because their positions are same and equal to 0 + $initialProducts = ['simple1002', 'simple1001', 'simple1000']; + $defaultStoreId = (int) $this->storeManager->getDefaultStoreView()->getId(); + $category = $this->getCategory(['name' => 'Category 999']); + $expectedProducts = array_keys($products); + $productIdsBySkus = $this->productResource->getProductsIdsBySkus($expectedProducts); + $postedProducts = []; + foreach ($products as $sku => $position) { + $postedProducts[$productIdsBySkus[$sku]] = $position; + } + $category->setPostedProducts($postedProducts); + $this->categoryResource->save($category); + // Indices should not be invalidated when adding/removing/reordering products in a category. + $categoryProductIndexer = $this->getIndexer(CategoryProductIndexer::INDEXER_ID); + $this->assertTrue( + $categoryProductIndexer->isValid(), + '"Indexed category/products association" indexer should not be invalidated.' + ); + $productCategoryIndexer = $this->getIndexer(ProductCategoryIndexer::INDEXER_ID); + $this->assertTrue( + $productCategoryIndexer->isValid(), + '"Indexed product/categories association" indexer should not be invalidated.' + ); + // catalog products is not update until partial reindex occurs + $collection = $this->getCategoryProducts($category, $defaultStoreId); + $this->assertEquals($initialProducts, $collection->getColumnValues('sku')); + // Execute MVIEW cron handler for cron job "indexer_update_all_views" + /** @var $mViewCron UpdateMview */ + $mViewCron = $this->objectManager->create(UpdateMview::class); + $mViewCron->execute(); + $collection = $this->getCategoryProducts($category, $defaultStoreId); + $this->assertEquals($expectedProducts, $collection->getColumnValues('sku')); + } + + /** + * @return array + */ + public function catalogProductChangesWithScheduledUpdateDataProvider(): array + { + return [ + 'change products position' => [ + [ + 'simple1002' => 1, + 'simple1000' => 2, + 'simple1001' => 3, + ] + ], + 'Add new product' => [ + [ + 'simple1002' => 1, + 'simple1000' => 2, + 'simple-1' => 3, + 'simple1001' => 4, + ] + ], + 'Delete product' => [ + [ + 'simple1002' => 1, + 'simple1000' => 2, + ] + ] + ]; + } + + /** + * @param CategoryModel $category + * @param int $defaultStoreId + * @return ProductCollection + */ + private function getCategoryProducts(CategoryModel $category, int $defaultStoreId) + { + /** @var ProductCollection $collection */ + $collection = $this->objectManager->create(ProductCollection::class); + $collection->setStoreId($defaultStoreId); + $collection->addCategoryFilter($category); + $collection->addAttributeToSort('position'); + return $collection; + } + + /** + * @param array $filters + * @return CategoryModel + */ + private function getCategory(array $filters): CategoryModel + { + /** @var CategoryCollection $categoryCollection */ + $categoryCollection = $this->objectManager->create(CategoryCollection::class); + foreach ($filters as $field => $value) { + $categoryCollection->addFieldToFilter($field, $value); + } + + return $categoryCollection->getFirstItem(); + } + + /** + * @param string $indexerId + * @return IndexerInterface + */ + private function getIndexer(string $indexerId): IndexerInterface + { + /** @var IndexerRegistry $indexerRegistry */ + $indexerRegistry = $this->objectManager->get(IndexerRegistry::class); + return $indexerRegistry->get($indexerId); + } + /** * Prepare image url for image data * diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_category_product_reindex_all.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_category_product_reindex_all.php new file mode 100644 index 0000000000000..3dfba9266cddc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_category_product_reindex_all.php @@ -0,0 +1,16 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Model\Indexer\Category\Product as CategoryProductIndexer; +use Magento\Framework\Indexer\IndexerRegistry; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var IndexerRegistry $indexRegistry */ +$indexRegistry = Bootstrap::getObjectManager()->get(IndexerRegistry::class); + +$model = $indexRegistry->get(CategoryProductIndexer::INDEXER_ID); +$model->reindexAll(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_product_category_reindex_all.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_product_category_reindex_all.php new file mode 100644 index 0000000000000..6143933ba3d6c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/catalog_product_category_reindex_all.php @@ -0,0 +1,16 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Model\Indexer\Product\Category as ProductCategoryIndexer; +use Magento\Framework\Indexer\IndexerRegistry; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var IndexerRegistry $indexRegistry */ +$indexRegistry = Bootstrap::getObjectManager()->get(IndexerRegistry::class); + +$model = $indexRegistry->get(ProductCategoryIndexer::INDEXER_ID); +$model->reindexAll(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/enable_catalog_product_reindex_schedule_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/enable_catalog_product_reindex_schedule_rollback.php index 429f89abb6ae7..8909b258b9f9c 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/enable_catalog_product_reindex_schedule_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/enable_catalog_product_reindex_schedule_rollback.php @@ -5,8 +5,14 @@ */ declare(strict_types=1); -use Magento\Catalog\Model\Indexer\Product\Price\Processor; +use Magento\Framework\Indexer\IndexerRegistry; use Magento\TestFramework\Helper\Bootstrap; -$indexerProcessor = Bootstrap::getObjectManager()->get(Processor::class); -$indexerProcessor->getIndexer()->setScheduled(false); +/** @var IndexerRegistry $indexRegistry */ +$indexRegistry = Bootstrap::getObjectManager()->get(IndexerRegistry::class); + +$model = $indexRegistry->get('catalog_category_product'); +$model->setScheduled(false); + +$model = $indexRegistry->get('catalog_product_category'); +$model->setScheduled(false); From 2195e725cb95d60dd57c717a98fc096768a695b0 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Mon, 30 Nov 2020 08:37:35 +0200 Subject: [PATCH 212/346] MC-38931: Product URL Rewrites are not removed when product removed from website --- .../GetProductUrlRewriteDataByStore.php | 76 +++ .../Products/AppendUrlRewritesToProducts.php | 159 ++++++ .../Product/GetUrlRewriteData.php | 94 ++++ ...ProductProcessUrlRewriteSavingObserver.php | 141 +++-- .../ProductToWebsiteChangeObserver.php | 104 ---- .../UpdateProductWebsiteUrlRewrites.php | 97 ++++ ...uctProcessUrlRewriteSavingObserverTest.php | 191 ++++--- .../etc/adminhtml/events.xml | 12 - app/code/Magento/CatalogUrlRewrite/etc/di.xml | 3 + .../GetStoresListByWebsiteIds.php | 45 ++ ...idByRequestPathAndStoreViewActionGroup.xml | 20 + ...SeveralWebsitesAndCheckURLRewritesTest.xml | 3 +- .../Api/ProductRepositoryInterfaceTest.php | 56 +- .../Model/ProductUrlRewriteTest.php | 7 + ...uctProcessUrlRewriteSavingObserverTest.php | 488 ++++++++++++++++-- .../UpdateProductWebsiteUrlRewritesTest.php | 72 +++ .../Model/StoreSwitcher/RewriteUrlTest.php | 2 +- 17 files changed, 1308 insertions(+), 262 deletions(-) create mode 100644 app/code/Magento/CatalogUrlRewrite/Model/Product/GetProductUrlRewriteDataByStore.php create mode 100644 app/code/Magento/CatalogUrlRewrite/Model/Products/AppendUrlRewritesToProducts.php create mode 100644 app/code/Magento/CatalogUrlRewrite/Model/ResourceModel/Product/GetUrlRewriteData.php delete mode 100644 app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php create mode 100644 app/code/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewrites.php delete mode 100644 app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml create mode 100644 app/code/Magento/Store/Model/StoreResolver/GetStoresListByWebsiteIds.php create mode 100644 app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminFilterUrlRewriteGridByRequestPathAndStoreViewActionGroup.xml create mode 100644 dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewritesTest.php diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Product/GetProductUrlRewriteDataByStore.php b/app/code/Magento/CatalogUrlRewrite/Model/Product/GetProductUrlRewriteDataByStore.php new file mode 100644 index 0000000000000..fbacddac1ce02 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Model/Product/GetProductUrlRewriteDataByStore.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogUrlRewrite\Model\Product; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\CatalogUrlRewrite\Model\ResourceModel\Product\GetUrlRewriteData; +use Magento\Store\Model\Store; + +/** + * Product data needed for url rewrite generation locator class + */ +class GetProductUrlRewriteDataByStore +{ + /** + * @var array + */ + private $urlRewriteData = []; + + /** + * @var GetUrlRewriteData + */ + private $getUrlRewriteData; + + /** + * @param GetUrlRewriteData $getUrlRewriteData + */ + public function __construct(GetUrlRewriteData $getUrlRewriteData) + { + $this->getUrlRewriteData = $getUrlRewriteData; + } + + /** + * Retrieves data for product by store + * + * @param ProductInterface $product + * @param int $storeId + * @return array + */ + public function execute(ProductInterface $product, int $storeId): array + { + $productId = $product->getId(); + if (isset($this->urlRewriteData[$productId][$storeId])) { + return $this->urlRewriteData[$productId][$storeId]; + } + if (empty($this->urlRewriteData[$productId])) { + $storesData = $this->getUrlRewriteData->execute($product); + foreach ($storesData as $storeData) { + $this->urlRewriteData[$productId][$storeData['store_id']] = [ + 'visibility' => (int)($storeData['visibility'] ?? $storesData[Store::DEFAULT_STORE_ID]['visibility']), + 'url_key' => $storeData['url_key'] ?? $storesData[Store::DEFAULT_STORE_ID]['url_key'], + ]; + } + } + + if (!isset($this->urlRewriteData[$productId][$storeId])) { + $this->urlRewriteData[$productId][$storeId] = $this->urlRewriteData[$productId][Store::DEFAULT_STORE_ID]; + } + + return $this->urlRewriteData[$productId][$storeId]; + } + + /** + * Clears product url rewrite data in local cache + * + * @param ProductInterface $product + */ + public function clearProductUrlRewriteDataCache(ProductInterface $product) + { + unset($this->urlRewriteData[$product->getId()]); + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Products/AppendUrlRewritesToProducts.php b/app/code/Magento/CatalogUrlRewrite/Model/Products/AppendUrlRewritesToProducts.php new file mode 100644 index 0000000000000..15d4aabf4246b --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Model/Products/AppendUrlRewritesToProducts.php @@ -0,0 +1,159 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogUrlRewrite\Model\Products; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Visibility; +use Magento\CatalogUrlRewrite\Model\Product\GetProductUrlRewriteDataByStore; +use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator; +use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; +use Magento\CatalogUrlRewrite\Service\V1\StoreViewService; +use Magento\Store\Model\Store; +use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException; +use Magento\UrlRewrite\Model\UrlPersistInterface; + +/** + * Update existing url rewrites or create new ones if needed + */ +class AppendUrlRewritesToProducts +{ + /** + * @var ProductUrlRewriteGenerator + */ + private $productUrlRewriteGenerator; + + /** + * @var StoreViewService + */ + private $storeViewService; + + /** + * @var ProductUrlPathGenerator + */ + private $productUrlPathGenerator; + + /** + * @var UrlPersistInterface + */ + private $urlPersist; + + /** + * @var GetProductUrlRewriteDataByStore + */ + private $getDataByStore; + + /** + * @param ProductUrlRewriteGenerator $urlRewriteGenerator + * @param StoreViewService $storeViewService + * @param ProductUrlPathGenerator $urlPathGenerator + * @param UrlPersistInterface $urlPersist + * @param GetProductUrlRewriteDataByStore $getDataByStore + */ + public function __construct( + ProductUrlRewriteGenerator $urlRewriteGenerator, + StoreViewService $storeViewService, + ProductUrlPathGenerator $urlPathGenerator, + UrlPersistInterface $urlPersist, + GetProductUrlRewriteDataByStore $getDataByStore + ) { + $this->productUrlRewriteGenerator = $urlRewriteGenerator; + $this->storeViewService = $storeViewService; + $this->productUrlPathGenerator = $urlPathGenerator; + $this->urlPersist = $urlPersist; + $this->getDataByStore = $getDataByStore; + } + + /** + * Update existing rewrites and add for specific stores websites + * + * @param ProductInterface[] $products + * @param array $storesToAdd + * @throws UrlAlreadyExistsException + */ + public function execute(array $products, array $storesToAdd): void + { + foreach ($products as $product) { + $forceGenerateDefault = false; + foreach ($storesToAdd as $storeId) { + if ($this->needGenerateUrlForStore($product, (int)$storeId)) { + $urls[] = $this->generateUrls($product, (int)$storeId); + } elseif ((int)$product->getStoreId() !== Store::DEFAULT_STORE_ID) { + $forceGenerateDefault = true; + } + } + if ($product->getStoreId() === Store::DEFAULT_STORE_ID + || $this->isProductAssignedToStore($product)) { + $product->unsUrlPath(); + $product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product)); + $urls[] = $this->productUrlRewriteGenerator->generate($product); + } + if ($forceGenerateDefault && $product->getStoreId() !== Store::DEFAULT_STORE_ID) { + $urls[] = $this->generateUrls($product, Store::DEFAULT_STORE_ID); + } + $this->getDataByStore->clearProductUrlRewriteDataCache($product); + } + if (!empty($urls)) { + $this->urlPersist->replace(array_merge(...$urls)); + } + } + + /** + * Generate urls for specific store + * + * @param ProductInterface $product + * @param int $storeId + * @return array + */ + private function generateUrls(ProductInterface $product, int $storeId): array + { + $storeData = $this->getDataByStore->execute($product, $storeId); + $origStoreId = $product->getStoreId(); + $origVisibility = $product->getVisibility(); + $origUrlKey = $product->getUrlKey(); + $product->setStoreId($storeId); + $product->setVisibility($storeData['visibility'] ?? Visibility::VISIBILITY_NOT_VISIBLE); + $product->setUrlKey($storeData['url_key'] ?? ''); + $product->unsUrlPath(); + $product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product)); + $urls = $this->productUrlRewriteGenerator->generate($product); + $product->setStoreId($origStoreId); + $product->setVisibility($origVisibility); + $product->setUrlKey($origUrlKey); + + return $urls; + } + + /** + * Does product has scope overridden url key value + * + * @param ProductInterface $product + * @param int $storeId + * @return bool + */ + private function needGenerateUrlForStore(ProductInterface $product, int $storeId): bool + { + return (int)$product->getStoreId() !== $storeId + && $this->storeViewService->doesEntityHaveOverriddenUrlKeyForStore( + $storeId, + $product->getId(), + Product::ENTITY + ); + } + + /** + * Is product still assigned to store which request is performed from + * + * @param ProductInterface $product + * @return bool + */ + private function isProductAssignedToStore(ProductInterface $product): bool + { + return in_array($product->getStoreId(), $product->getStoreIds()); + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/Model/ResourceModel/Product/GetUrlRewriteData.php b/app/code/Magento/CatalogUrlRewrite/Model/ResourceModel/Product/GetUrlRewriteData.php new file mode 100644 index 0000000000000..f4cef73a040e8 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Model/ResourceModel/Product/GetUrlRewriteData.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogUrlRewrite\Model\ResourceModel\Product; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product; +use Magento\Eav\Model\Config; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Select; +use Magento\Framework\EntityManager\MetadataPool; + +/** + * Fetch product url rewrite data from database + */ +class GetUrlRewriteData +{ + /** + * @var MetadataPool + */ + private $metadataPool; + + /** + * @var ResourceConnection + */ + private $resource; + + /** + * @var Config + */ + private $eavConfig; + + /** + * @param MetadataPool $metadataPool + * @param ResourceConnection $connection + * @param Config $eavConfig + */ + public function __construct( + MetadataPool $metadataPool, + ResourceConnection $connection, + Config $eavConfig + ) { + $this->metadataPool = $metadataPool; + $this->resource = $connection; + $this->eavConfig = $eavConfig; + } + + /** + * Fetches product store data required for url key generation + * + * @param ProductInterface $product + * @return array + */ + public function execute(ProductInterface $product): array + { + $metadata = $this->metadataPool->getMetadata(ProductInterface::class); + $linkField = $metadata->getLinkField(); + $connection = $this->resource->getConnection(); + $visibilityAttribute = $this->eavConfig->getAttribute(Product::ENTITY, 'visibility'); + $urlKeyAttribute = $this->eavConfig->getAttribute(Product::ENTITY, 'url_key'); + $visibilitySelect = $connection->select() + ->from(['visibility' => $visibilityAttribute->getBackendTable()]) + ->joinRight( + ['url_key' => $urlKeyAttribute->getBackendTable()], + 'url_key.' . $linkField . ' = visibility.' . $linkField . ' AND url_key.store_id = visibility.store_id' + . ' AND url_key.attribute_id = ' . $urlKeyAttribute->getId(), + ['url_key.value as url_key'] + ) + ->reset(Select::COLUMNS) + ->columns(['url_key.store_id', 'url_key.value AS url_key', 'visibility.value AS visibility']) + ->where('visibility.' . $linkField . ' = ?', $product->getData($linkField)) + ->where('visibility.attribute_id = ?', $visibilityAttribute->getId()); + $urlKeySelect = $connection->select() + ->from(['url_key' => $urlKeyAttribute->getBackendTable()]) + ->joinLeft( + ['visibility' => $visibilityAttribute->getBackendTable()], + 'url_key.' . $linkField . ' = visibility.' . $linkField . ' AND url_key.store_id = visibility.store_id' + . ' AND visibility.attribute_id = ' . $visibilityAttribute->getId(), + ['visibility.value as visibility'] + ) + ->reset(Select::COLUMNS) + ->columns(['url_key.store_id', 'url_key.value AS url_key', 'visibility.value as visibility']) + ->where('url_key.' . $linkField . ' = ?', $product->getData($linkField)) + ->where('url_key.attribute_id = ?', $urlKeyAttribute->getId()); + + $select = $connection->select()->union([$visibilitySelect, $urlKeySelect], Select::SQL_UNION); + + return $connection->fetchAll($select); + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php index 6eda8dd0b61ee..512340354172e 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserver.php @@ -3,73 +3,156 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\CatalogUrlRewrite\Observer; use Magento\Catalog\Model\Product; -use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator; +use Magento\Catalog\Model\Product\Visibility; +use Magento\CatalogUrlRewrite\Model\Products\AppendUrlRewritesToProducts; use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; -use Magento\Framework\App\ObjectManager; -use Magento\UrlRewrite\Model\UrlPersistInterface; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreResolver\GetStoresListByWebsiteIds; +use Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException; +use Magento\UrlRewrite\Model\UrlPersistInterface; +use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; /** * Class ProductProcessUrlRewriteSavingObserver + * + * Generates urls for product url rewrites */ class ProductProcessUrlRewriteSavingObserver implements ObserverInterface { /** - * @var ProductUrlRewriteGenerator + * @var UrlPersistInterface + */ + private $urlPersist; + + /** + * @var AppendUrlRewritesToProducts */ - private $productUrlRewriteGenerator; + private $appendRewrites; /** - * @var UrlPersistInterface + * @var ScopeConfigInterface */ - private $urlPersist; + private $scopeConfig; /** - * @var ProductUrlPathGenerator + * @var GetStoresListByWebsiteIds */ - private $productUrlPathGenerator; + private $getStoresList; /** - * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator * @param UrlPersistInterface $urlPersist - * @param ProductUrlPathGenerator|null $productUrlPathGenerator + * @param AppendUrlRewritesToProducts|null $appendRewrites + * @param ScopeConfigInterface $scopeConfig + * @param GetStoresListByWebsiteIds $getStoresList */ public function __construct( - ProductUrlRewriteGenerator $productUrlRewriteGenerator, UrlPersistInterface $urlPersist, - ProductUrlPathGenerator $productUrlPathGenerator = null + AppendUrlRewritesToProducts $appendRewrites, + ScopeConfigInterface $scopeConfig, + GetStoresListByWebsiteIds $getStoresList ) { - $this->productUrlRewriteGenerator = $productUrlRewriteGenerator; $this->urlPersist = $urlPersist; - $this->productUrlPathGenerator = $productUrlPathGenerator ?: ObjectManager::getInstance() - ->get(ProductUrlPathGenerator::class); + $this->appendRewrites = $appendRewrites; + $this->scopeConfig = $scopeConfig; + $this->getStoresList = $getStoresList; } /** * Generate urls for UrlRewrite and save it in storage * - * @param \Magento\Framework\Event\Observer $observer + * @param Observer $observer * @return void - * @throws \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException + * @throws UrlAlreadyExistsException */ - public function execute(\Magento\Framework\Event\Observer $observer) + public function execute(Observer $observer) { /** @var Product $product */ $product = $observer->getEvent()->getProduct(); - if ($product->dataHasChangedFor('url_key') - || $product->getIsChangedCategories() - || $product->getIsChangedWebsites() - || $product->dataHasChangedFor('visibility') - ) { - if ($product->isVisibleInSiteVisibility()) { - $product->unsUrlPath(); - $product->setUrlPath($this->productUrlPathGenerator->getUrlPath($product)); - $this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product)); - } + if ($this->isNeedUpdateRewrites($product)) { + $this->deleteObsoleteRewrites($product); + $oldWebsiteIds = $product->getOrigData('website_ids') ?? []; + $storesToAdd = $this->getStoresList->execute( + array_diff($product->getWebsiteIds(), $oldWebsiteIds) + ); + $this->appendRewrites->execute([$product], $storesToAdd); } } + + /** + * Remove obsolete Url rewrites + * + * @param Product $product + */ + private function deleteObsoleteRewrites(Product $product): void + { + //do not perform redundant delete request for new product + if ($product->getOrigData('entity_id') === null) { + return; + } + $oldWebsiteIds = $product->getOrigData('website_ids') ?? []; + $storesToRemove = $this->getStoresList->execute( + array_diff($oldWebsiteIds, $product->getWebsiteIds()) + ); + if ((int)$product->getVisibility() === Visibility::VISIBILITY_NOT_VISIBLE) { + $isGlobalScope = $product->getStoreId() == Store::DEFAULT_STORE_ID; + $storesToRemove[] = $isGlobalScope ? $product->getStoreIds() : $product->getStoreId(); + } + if ($storesToRemove) { + $this->urlPersist->deleteByData( + [ + UrlRewrite::ENTITY_ID => $product->getId(), + UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, + UrlRewrite::STORE_ID => $storesToRemove, + ] + ); + } + } + + /** + * Is website assignment updated + * + * @param Product $product + * @return bool + */ + private function isWebsiteChanged(Product $product) + { + $oldWebsiteIds = $product->getOrigData('website_ids'); + $newWebsiteIds = $product->getWebsiteIds(); + + return array_diff($oldWebsiteIds, $newWebsiteIds) || array_diff($newWebsiteIds, $oldWebsiteIds); + } + + + /** + * Is product rewrites need to be updated + * + * @param Product $product + * @return bool + */ + private function isNeedUpdateRewrites(Product $product): bool + { + return ($product->dataHasChangedFor('url_key') + && (int)$product->getVisibility() !== Visibility::VISIBILITY_NOT_VISIBLE) + || ($product->getIsChangedCategories() && $this->isGenerateCategoryProductRewritesEnabled()) + || $this->isWebsiteChanged($product) + || $product->dataHasChangedFor('visibility'); + } + + /** + * Return product use category path in rewrite config value + * + * @return bool + */ + private function isGenerateCategoryProductRewritesEnabled(): bool + { + return $this->scopeConfig->isSetFlag('catalog/seo/generate_category_product_rewrites'); + } } diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php deleted file mode 100644 index 44b47faf3d4b8..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php +++ /dev/null @@ -1,104 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\CatalogUrlRewrite\Observer; - -use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Catalog\Model\Product\Visibility; -use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; -use Magento\Framework\App\RequestInterface; -use Magento\Framework\Event\ObserverInterface; -use Magento\Store\Model\Store; -use Magento\UrlRewrite\Model\UrlPersistInterface; -use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; -use Magento\Store\Api\StoreWebsiteRelationInterface; -use Magento\Framework\App\ObjectManager; - -/** - * Observer to assign the products to website - */ -class ProductToWebsiteChangeObserver implements ObserverInterface -{ - /** - * @var ProductUrlRewriteGenerator - */ - protected $productUrlRewriteGenerator; - - /** - * @var UrlPersistInterface - */ - protected $urlPersist; - - /** - * @var ProductRepositoryInterface - */ - protected $productRepository; - - /** - * @var RequestInterface - */ - protected $request; - - /** - * @var StoreWebsiteRelationInterface - */ - private $storeWebsiteRelation; - - /** - * @param ProductUrlRewriteGenerator $productUrlRewriteGenerator - * @param UrlPersistInterface $urlPersist - * @param ProductRepositoryInterface $productRepository - * @param RequestInterface $request - * @param StoreWebsiteRelationInterface $storeWebsiteRelation - */ - public function __construct( - ProductUrlRewriteGenerator $productUrlRewriteGenerator, - UrlPersistInterface $urlPersist, - ProductRepositoryInterface $productRepository, - RequestInterface $request, - StoreWebsiteRelationInterface $storeWebsiteRelation = null - ) { - $this->productUrlRewriteGenerator = $productUrlRewriteGenerator; - $this->urlPersist = $urlPersist; - $this->productRepository = $productRepository; - $this->request = $request; - $this->storeWebsiteRelation = $storeWebsiteRelation ?: - ObjectManager::getInstance()->get(StoreWebsiteRelationInterface::class); - } - - /** - * Generate urls for UrlRewrite and save it in storage - * - * @param \Magento\Framework\Event\Observer $observer - * @return void - */ - public function execute(\Magento\Framework\Event\Observer $observer) - { - foreach ($observer->getEvent()->getProducts() as $productId) { - $product = $this->productRepository->getById( - $productId, - false, - $this->request->getParam('store_id', Store::DEFAULT_STORE_ID) - ); - - if (!empty($this->productUrlRewriteGenerator->generate($product))) { - if ($this->request->getParam('remove_website_ids')) { - foreach ($this->request->getParam('remove_website_ids') as $webId) { - foreach ($this->storeWebsiteRelation->getStoreByWebsiteId($webId) as $storeId) { - $this->urlPersist->deleteByData([ - UrlRewrite::ENTITY_ID => $product->getId(), - UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, - UrlRewrite::STORE_ID => $storeId - ]); - } - } - } - if ($product->getVisibility() != Visibility::VISIBILITY_NOT_VISIBLE) { - $this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product)); - } - } - } - } -} diff --git a/app/code/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewrites.php b/app/code/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewrites.php new file mode 100644 index 0000000000000..f9c605ab489a5 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewrites.php @@ -0,0 +1,97 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogUrlRewrite\Plugin\Catalog\Model\Product; + +use Magento\Catalog\Model\Product\Action as ProductAction; +use Magento\Catalog\Model\ResourceModel\Product\Collection; +use Magento\CatalogUrlRewrite\Model\Products\AppendUrlRewritesToProducts; +use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; +use Magento\Store\Api\StoreWebsiteRelationInterface; +use Magento\Store\Model\StoreResolver\GetStoresListByWebsiteIds; +use Magento\UrlRewrite\Model\UrlPersistInterface; +use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; + +/** + * Update URL rewrites after website change + */ +class UpdateProductWebsiteUrlRewrites +{ + /** + * @var UrlPersistInterface + */ + private $urlPersist; + + /** + * @var Collection + */ + private $productCollection; + + /** + * @var AppendUrlRewritesToProducts + */ + private $appendRewrites; + + /** + * @var GetStoresListByWebsiteIds + */ + private $getStoresList; + + /** + * @param UrlPersistInterface $urlPersist + * @param Collection $productCollection + * @param AppendUrlRewritesToProducts $appendRewrites + * @param GetStoresListByWebsiteIds $getStoresList + */ + public function __construct( + UrlPersistInterface $urlPersist, + Collection $productCollection, + AppendUrlRewritesToProducts $appendRewrites, + GetStoresListByWebsiteIds $getStoresList + ) { + $this->urlPersist = $urlPersist; + $this->productCollection = $productCollection; + $this->appendRewrites = $appendRewrites; + $this->getStoresList = $getStoresList; + } + + /** + * Update url rewrites after website changes + * + * @param ProductAction $subject + * @param void $result + * @param array $productIds + * @param array $websiteIds + * @param string $type + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterUpdateWebsites( + ProductAction $subject, + $result, + array $productIds, + array $websiteIds, + string $type + ): void { + if (empty($websiteIds)) { + return; + } + $storeIds = $this->getStoresList->execute($websiteIds); + // Remove the URLs from websites this product no longer belongs to + if ($type == 'remove') { + $this->urlPersist->deleteByData( + [ + UrlRewrite::ENTITY_ID => $productIds, + UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, + UrlRewrite::STORE_ID => $storeIds, + ] + ); + } else { + $collection = $this->productCollection->addFieldToFilter('entity_id', ['in' => implode(',', $productIds)]); + $this->appendRewrites->execute($collection->getItems(), $storeIds); + } + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php index 30f7608504c23..64f7acb1feda2 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php @@ -1,4 +1,5 @@ <?php + /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. @@ -8,11 +9,13 @@ namespace Magento\CatalogUrlRewrite\Test\Unit\Observer; use Magento\Catalog\Model\Product; -use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; +use Magento\CatalogUrlRewrite\Model\Products\AppendUrlRewritesToProducts; use Magento\CatalogUrlRewrite\Observer\ProductProcessUrlRewriteSavingObserver; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Event; use Magento\Framework\Event\Observer; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\ObjectManagerInterface; +use Magento\Store\Api\StoreWebsiteRelationInterface; use Magento\UrlRewrite\Model\UrlPersistInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -44,12 +47,7 @@ class ProductProcessUrlRewriteSavingObserverTest extends TestCase protected $product; /** - * @var ProductUrlRewriteGenerator|MockObject - */ - protected $productUrlRewriteGenerator; - - /** - * @var ObjectManager + * @var ObjectManagerInterface */ protected $objectManager; @@ -59,14 +57,39 @@ class ProductProcessUrlRewriteSavingObserverTest extends TestCase protected $model; /** - * Set up + * @var StoreWebsiteRelationInterface|MockObject + */ + private $storeRelation; + + /** + * @var AppendUrlRewritesToProducts|MockObject + */ + private $appendRewrites; + + /** + * @var ScopeConfigInterface|MockObject + */ + private $scopeConfig; + + /** + * @inheritdoc */ protected function setUp(): void { $this->urlPersist = $this->getMockForAbstractClass(UrlPersistInterface::class); $this->product = $this->getMockBuilder(Product::class) ->addMethods(['getIsChangedWebsites', 'getIsChangedCategories']) - ->onlyMethods(['getId', 'dataHasChangedFor', 'isVisibleInSiteVisibility', 'getStoreId']) + ->onlyMethods( + [ + 'getId', + 'dataHasChangedFor', + 'getVisibility', + 'getStoreId', + 'getWebsiteIds', + 'getOrigData', + 'getCategoryCollection', + ] + ) ->disableOriginalConstructor() ->getMock(); $this->product->expects($this->any())->method('getId')->willReturn(3); @@ -77,20 +100,26 @@ protected function setUp(): void $this->event->expects($this->any())->method('getProduct')->willReturn($this->product); $this->observer = $this->createPartialMock(Observer::class, ['getEvent']); $this->observer->expects($this->any())->method('getEvent')->willReturn($this->event); - $this->productUrlRewriteGenerator = $this->createPartialMock( - ProductUrlRewriteGenerator::class, - ['generate'] - ); - $this->productUrlRewriteGenerator->expects($this->any()) - ->method('generate') - ->willReturn([3 => 'rewrite']); - $this->objectManager = new ObjectManager($this); - $this->model = $this->objectManager->getObject( - ProductProcessUrlRewriteSavingObserver::class, - [ - 'productUrlRewriteGenerator' => $this->productUrlRewriteGenerator, - 'urlPersist' => $this->urlPersist - ] + $this->storeRelation = $this->getMockBuilder(StoreWebsiteRelationInterface::class) + ->onlyMethods(['getStoreByWebsiteId']) + ->disableOriginalConstructor() + ->getMock(); + + $this->scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class) + ->onlyMethods(['isSetFlag']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->appendRewrites = $this->getMockBuilder(AppendUrlRewritesToProducts::class) + ->onlyMethods(['execute']) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new ProductProcessUrlRewriteSavingObserver( + $this->urlPersist, + $this->storeRelation, + $this->appendRewrites, + $this->scopeConfig ); } @@ -103,53 +132,59 @@ public function urlKeyDataProvider() { return [ 'url changed' => [ - 'isChangedUrlKey' => true, - 'isChangedVisibility' => false, - 'isChangedWebsites' => false, - 'isChangedCategories' => false, - 'visibilityResult' => true, - 'expectedReplaceCount' => 1, + 'isChangedUrlKey' => true, + 'isChangedVisibility' => false, + 'isChangedWebsites' => false, + 'isChangedCategories' => false, + 'visibilityResult' => 4, + 'expectedReplaceCount' => 1, + 'websitesWithProduct' => [1], ], 'no chnages' => [ - 'isChangedUrlKey' => false, - 'isChangedVisibility' => false, - 'isChangedWebsites' => false, - 'isChangedCategories' => false, - 'visibilityResult' => true, - 'expectedReplaceCount' => 0 + 'isChangedUrlKey' => false, + 'isChangedVisibility' => false, + 'isChangedWebsites' => false, + 'isChangedCategories' => false, + 'visibilityResult' => 4, + 'expectedReplaceCount' => 0, + 'websitesWithProduct' => [1], ], 'visibility changed' => [ - 'isChangedUrlKey' => false, - 'isChangedVisibility' => true, - 'isChangedWebsites' => false, - 'isChangedCategories' => false, - 'visibilityResult' => true, - 'expectedReplaceCount' => 1 + 'isChangedUrlKey' => false, + 'isChangedVisibility' => true, + 'isChangedWebsites' => false, + 'isChangedCategories' => false, + 'visibilityResult' => 4, + 'expectedReplaceCount' => 1, + 'websitesWithProduct' => [1], ], 'websites changed' => [ - 'isChangedUrlKey' => false, - 'isChangedVisibility' => false, - 'isChangedWebsites' => true, - 'isChangedCategories' => false, - 'visibilityResult' => true, - 'expectedReplaceCount' => 1 + 'isChangedUrlKey' => false, + 'isChangedVisibility' => false, + 'isChangedWebsites' => true, + 'isChangedCategories' => false, + 'visibilityResult' => 4, + 'expectedReplaceCount' => 1, + 'websitesWithProduct' => [1], ], 'categories changed' => [ - 'isChangedUrlKey' => false, - 'isChangedVisibility' => false, - 'isChangedWebsites' => false, - 'isChangedCategories' => true, - 'visibilityResult' => true, - 'expectedReplaceCount' => 1 + 'isChangedUrlKey' => false, + 'isChangedVisibility' => false, + 'isChangedWebsites' => false, + 'isChangedCategories' => true, + 'visibilityResult' => 4, + 'expectedReplaceCount' => 1, + 'websitesWithProduct' => [1], ], 'url changed invisible' => [ - 'isChangedUrlKey' => true, - 'isChangedVisibility' => false, - 'isChangedWebsites' => false, - 'isChangedCategories' => false, - 'visibilityResult' => false, - 'expectedReplaceCount' => 0 + 'isChangedUrlKey' => true, + 'isChangedVisibility' => false, + 'isChangedWebsites' => false, + 'isChangedCategories' => false, + 'visibilityResult' => 1, + 'expectedReplaceCount' => 0, + 'websitesWithProduct' => [1], ], ]; } @@ -161,6 +196,7 @@ public function urlKeyDataProvider() * @param bool $isChangedCategories * @param bool $visibilityResult * @param int $expectedReplaceCount + * @param array $websitesWithProduct * * @dataProvider urlKeyDataProvider */ @@ -170,16 +206,19 @@ public function testExecuteUrlKey( $isChangedWebsites, $isChangedCategories, $visibilityResult, - $expectedReplaceCount + $expectedReplaceCount, + $websitesWithProduct ) { $this->product->expects($this->any())->method('getStoreId')->willReturn(12); $this->product->expects($this->any()) ->method('dataHasChangedFor') - ->willReturnMap([ - ['visibility', $isChangedVisibility], - ['url_key', $isChangedUrlKey] - ]); + ->willReturnMap( + [ + ['visibility', $isChangedVisibility], + ['url_key', $isChangedUrlKey], + ] + ); $this->product->expects($this->any()) ->method('getIsChangedWebsites') @@ -189,13 +228,27 @@ public function testExecuteUrlKey( ->method('getIsChangedCategories') ->willReturn($isChangedCategories); + $this->storeRelation->expects($this->any()) + ->method('getStoreByWebsiteId') + ->willReturn([3]); + + $this->product->expects($this->any())->method('getWebsiteIds')->will( + $this->returnValue($websitesWithProduct) + ); + $this->product->expects($this->any()) - ->method('isVisibleInSiteVisibility') + ->method('getVisibility') ->willReturn($visibilityResult); - $this->urlPersist->expects($this->exactly($expectedReplaceCount)) - ->method('replace') - ->with([3 => 'rewrite']); + $this->product->expects($this->any()) + ->method('getOrigData') + ->willReturn($isChangedWebsites ? [] : $websitesWithProduct); + $this->scopeConfig->expects($this->any()) + ->method('isSetFlag') + ->willReturn(true); + + $this->appendRewrites->expects($this->exactly($expectedReplaceCount)) + ->method('execute'); $this->model->execute($this->observer); } diff --git a/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml b/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml deleted file mode 100644 index 9c4a8aaf41231..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/etc/adminhtml/events.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> - <event name="catalog_product_to_website_change"> - <observer name="catalog_product_to_website_change" instance="Magento\CatalogUrlRewrite\Observer\ProductToWebsiteChangeObserver"/> - </event> -</config> diff --git a/app/code/Magento/CatalogUrlRewrite/etc/di.xml b/app/code/Magento/CatalogUrlRewrite/etc/di.xml index 5fb7d33546d60..d22816243f64c 100644 --- a/app/code/Magento/CatalogUrlRewrite/etc/di.xml +++ b/app/code/Magento/CatalogUrlRewrite/etc/di.xml @@ -27,6 +27,9 @@ <type name="Magento\CatalogUrlRewrite\Model\Storage\DbStorage"> <plugin name="dynamic_storage_plugin" type="Magento\CatalogUrlRewrite\Plugin\DynamicCategoryRewrites"/> </type> + <type name="Magento\Catalog\Model\Product\Action"> + <plugin name="update_url_rewrites_after_websites_update_plugin" type="Magento\CatalogUrlRewrite\Plugin\Catalog\Model\Product\UpdateProductWebsiteUrlRewrites"/> + </type> <type name="Magento\CatalogUrlRewrite\Model\Map\UrlRewriteFinder"> <arguments> <argument name="urlRewriteClassNames" xsi:type="array"> diff --git a/app/code/Magento/Store/Model/StoreResolver/GetStoresListByWebsiteIds.php b/app/code/Magento/Store/Model/StoreResolver/GetStoresListByWebsiteIds.php new file mode 100644 index 0000000000000..416537caaf0e0 --- /dev/null +++ b/app/code/Magento/Store/Model/StoreResolver/GetStoresListByWebsiteIds.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Store\Model\StoreResolver; + +use Magento\Store\Api\StoreWebsiteRelationInterface; + +/** + * Retrieves store ids list array by website ids array + */ +class GetStoresListByWebsiteIds +{ + /** + * @var StoreWebsiteRelationInterface + */ + private $storeWebsiteRelation; + + /** + * @param StoreWebsiteRelationInterface $storeWebsiteRelation + */ + public function __construct(StoreWebsiteRelationInterface $storeWebsiteRelation) + { + $this->storeWebsiteRelation = $storeWebsiteRelation; + } + + /** + * Retrieve list of stores by website ids + * + * @param array $websiteIds + * @return array + */ + public function execute(array $websiteIds): array + { + $storeIdsArray = []; + foreach ($websiteIds as $websiteId) { + $storeIdsArray[] = $this->storeWebsiteRelation->getStoreByWebsiteId($websiteId); + } + + return array_merge([], ...$storeIdsArray); + } +} diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminFilterUrlRewriteGridByRequestPathAndStoreViewActionGroup.xml b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminFilterUrlRewriteGridByRequestPathAndStoreViewActionGroup.xml new file mode 100644 index 0000000000000..2e80fa0f798a6 --- /dev/null +++ b/app/code/Magento/UrlRewrite/Test/Mftf/ActionGroup/AdminFilterUrlRewriteGridByRequestPathAndStoreViewActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFilterUrlRewriteGridByRequestPathAndStoreViewActionGroup" extends="AdminSearchByRequestPathActionGroup"> + <annotations> + <description>Goes to the Admin URL Rewrite grid page. Searches the grid based on the provided Redirect Path and StoreView name. Validates that the provided Redirect Path, Type and Target Path are present and correct in the grid.</description> + </annotations> + <arguments> + <argument name="storeView" type="string"/> + </arguments> + <selectOption selector="{{AdminDataGridHeaderSection.filterFieldSelect('store_id')}}" userInput="{{storeView}}" stepKey="fillStoreView" after="fillRedirectPathFilter"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml index c14d0b175d2c0..ccd4297312f44 100644 --- a/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml +++ b/app/code/Magento/UrlRewrite/Test/Mftf/Test/AdminCreateProductWithSeveralWebsitesAndCheckURLRewritesTest.xml @@ -109,10 +109,11 @@ </actionGroup> <grabFromCurrentUrl stepKey="productId" regex="#\/([0-9]*)?\/$#"/> <!-- Open Url Rewrite page and verify new Redirect Path, RedirectType and Target Path for the grabbed product Id --> - <actionGroup ref="AdminSearchByRequestPathActionGroup" stepKey="searchPath1"> + <actionGroup ref="AdminFilterUrlRewriteGridByRequestPathAndStoreViewActionGroup" stepKey="searchPath1"> <argument name="redirectPath" value="$$createProduct.name$$.html"/> <argument name="redirectType" value="No"/> <argument name="targetPath" value="catalog/product/view/id/{$productId}"/> + <argument name="storeView" value="{{storeViewData.name}}"/> </actionGroup> <actionGroup ref="AssertAdminStoreValueIsSetForUrlRewriteActionGroup" stepKey="seeStoreValueForProductId"> diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php index 1b18949b0ac5b..d77737edadafa 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php @@ -25,6 +25,7 @@ use Magento\Framework\Webapi\Exception as HTTPExceptionCodes; use Magento\Integration\Api\AdminTokenServiceInterface; use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Api\StoreWebsiteRelationInterface; use Magento\Store\Model\Store; use Magento\Store\Model\StoreRepository; use Magento\Store\Model\Website; @@ -254,6 +255,59 @@ public function testUpdateWithDeleteWebsites() ); } + /** + * Test removing association between product and website 1 then check url rewrite removed + * Assign website back and check rewrite generated + * + * @magentoApiDataFixture Magento/Catalog/_files/product_two_websites.php + */ + public function testUpdateRewriteWithChangeWebsites() + { + /** @var Website $website */ + $website = $this->loadWebsiteByCode('test'); + + $productBuilder[ProductInterface::SKU] = 'simple-on-two-websites'; + $productBuilder[ProductInterface::EXTENSION_ATTRIBUTES_KEY] = [ + 'website_ids' => [ + $website->getId(), + ], + ]; + $objectManager = Bootstrap::getObjectManager(); + /** @var StoreWebsiteRelationInterface $storeWebsiteRelation */ + $storeWebsiteRelation = $objectManager->get(StoreWebsiteRelationInterface::class); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $objectManager->get(ProductRepositoryInterface::class); + + $baseWebsite = $this->loadWebsiteByCode('base'); + $storeIds = $storeWebsiteRelation->getStoreByWebsiteId($baseWebsite->getId()); + $product = $productRepository->get($productBuilder[ProductInterface::SKU], false, reset($storeIds)); + $this->assertStringContainsString( + $product->getUrlKey() . '.html', + $product->getProductUrl() + ); + + $this->updateProduct($productBuilder); + + $product->setRequestPath(''); + $this->assertStringNotContainsString( + $product->getUrlKey() . '.html', + $product->getProductUrl() + ); + $productBuilder[ProductInterface::EXTENSION_ATTRIBUTES_KEY] = [ + 'website_ids' => [ + $website->getId(), + $baseWebsite->getId(), + ], + ]; + + $this->updateProduct($productBuilder); + $product->setRequestPath(''); + $this->assertStringContainsString( + $product->getUrlKey() . '.html', + $product->getProductUrl() + ); + } + /** * Test removing all website associations * @@ -264,7 +318,7 @@ public function testDeleteAllWebsiteAssociations() $productBuilder[ProductInterface::SKU] = 'unique-simple-azaza'; $websitesData = [ - 'website_ids' => [] + 'website_ids' => [], ]; $productBuilder[ProductInterface::EXTENSION_ATTRIBUTES_KEY] = $websitesData; $response = $this->updateProduct($productBuilder); diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteTest.php index 0432649455abe..e3e3d3e3972e5 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/ProductUrlRewriteTest.php @@ -85,6 +85,7 @@ public function productDataProvider(): array 'sku' => 'test-product', 'name' => 'test product', 'price' => 150, + 'website_ids' => [1] ], 'expected_data' => [ [ @@ -104,6 +105,7 @@ public function productDataProvider(): array 'name' => 'test product', 'price' => 150, 'url_key' => 'test-product-url-key', + 'website_ids' => [1] ], 'expected_data' => [ [ @@ -123,6 +125,7 @@ public function productDataProvider(): array 'name' => 'test product', 'price' => 150, 'url_key' => 'test-product-url-key', + 'website_ids' => [1] ], 'expected_data' => [], ], @@ -201,6 +204,7 @@ public function existingUrlKeyProvider(): array 'name' => 'test-simple-product', 'price' => 150, 'url_key' => 'simple-product', + 'store_ids' => [1] ], 'with_autogenerated_existing_product_url_key' => [ 'type_id' => Type::TYPE_SIMPLE, @@ -208,6 +212,7 @@ public function existingUrlKeyProvider(): array 'sku' => 'test-simple-product', 'name' => 'simple product', 'price' => 150, + 'store_ids' => [1] ], 'with_specified_existing_category_url_key' => [ 'type_id' => Type::TYPE_SIMPLE, @@ -216,6 +221,7 @@ public function existingUrlKeyProvider(): array 'name' => 'test-simple-product', 'price' => 150, 'url_key' => 'category-1', + 'store_ids' => [1] ], 'with_autogenerated_existing_category_url_key' => [ 'type_id' => Type::TYPE_SIMPLE, @@ -223,6 +229,7 @@ public function existingUrlKeyProvider(): array 'sku' => 'test-simple-product', 'name' => 'category 1', 'price' => 150, + 'store_ids' => [1] ], ], ]; diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php index c3efd660792c0..82631220730de 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Observer/ProductProcessUrlRewriteSavingObserverTest.php @@ -5,25 +5,46 @@ */ namespace Magento\CatalogUrlRewrite\Observer; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Framework\ObjectManagerInterface; +use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\UrlRewrite\Model\UrlFinderInterface; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; -use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator; +use PHPUnit\Framework\TestCase; /** * @magentoAppArea adminhtml * @magentoDbIsolation disabled */ -class ProductProcessUrlRewriteSavingObserverTest extends \PHPUnit\Framework\TestCase +class ProductProcessUrlRewriteSavingObserverTest extends TestCase { - /** @var \Magento\Framework\ObjectManagerInterface */ - protected $objectManager; + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; /** * Set up */ protected function setUp(): void { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = Bootstrap::getObjectManager(); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); } /** @@ -32,8 +53,8 @@ protected function setUp(): void */ private function getActualResults(array $filter) { - /** @var \Magento\UrlRewrite\Model\UrlFinderInterface $urlFinder */ - $urlFinder = $this->objectManager->get(\Magento\UrlRewrite\Model\UrlFinderInterface::class); + /** @var UrlFinderInterface $urlFinder */ + $urlFinder = $this->objectManager->get(UrlFinderInterface::class); $actualResults = []; foreach ($urlFinder->findAllByData($filter) as $url) { $actualResults[] = [ @@ -53,16 +74,14 @@ private function getActualResults(array $filter) */ public function testUrlKeyHasChangedInGlobalContext() { - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository*/ - $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); - /** @var \Magento\Catalog\Model\Product $product*/ - $product = $productRepository->get('product1'); + $testStore1 = $this->storeManager->getStore('default'); + $testStore4 = $this->storeManager->getStore('test'); - /** @var StoreManagerInterface $storeManager */ - $storeManager = $this->objectManager->get(StoreManagerInterface::class); - $storeManager->setCurrentStore(0); + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + + /** @var Product $product*/ + $product = $this->productRepository->get('product1'); - $testStore = $storeManager->getStore('test'); $productFilter = [ UrlRewrite::ENTITY_TYPE => 'product', ]; @@ -73,14 +92,14 @@ public function testUrlKeyHasChangedInGlobalContext() 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => 1, + 'store_id' => $testStore1->getId(), ], [ 'request_path' => "product-1.html", 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => $testStore->getId(), + 'store_id' => $testStore4->getId(), ], ]; $actual = $this->getActualResults($productFilter); @@ -91,7 +110,7 @@ public function testUrlKeyHasChangedInGlobalContext() $product->setData('save_rewrites_history', true); $product->setUrlKey('new-url'); $product->setUrlPath('new-path'); - $product->save(); + $this->productRepository->save($product); $expected = [ [ @@ -99,28 +118,28 @@ public function testUrlKeyHasChangedInGlobalContext() 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => 1, + 'store_id' => $testStore1->getId(), ], [ 'request_path' => "new-url.html", 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => $testStore->getId(), + 'store_id' => $testStore4->getId(), ], [ 'request_path' => "product-1.html", 'target_path' => "new-url.html", 'is_auto_generated' => 0, 'redirect_type' => 301, - 'store_id' => 1, + 'store_id' => $testStore1->getId(), ], [ 'request_path' => "product-1.html", 'target_path' => "new-url.html", 'is_auto_generated' => 0, 'redirect_type' => 301, - 'store_id' => $testStore->getId(), + 'store_id' => $testStore4->getId(), ], ]; @@ -136,16 +155,13 @@ public function testUrlKeyHasChangedInGlobalContext() */ public function testUrlKeyHasChangedInStoreviewContextWithPermanentRedirection() { - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository*/ - $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); - /** @var \Magento\Catalog\Model\Product $product*/ - $product = $productRepository->get('product1'); + $testStore1 = $this->storeManager->getStore('default'); + $testStore4 = $this->storeManager->getStore('test'); - /** @var StoreManagerInterface $storeManager */ - $storeManager = $this->objectManager->get(StoreManagerInterface::class); - $storeManager->setCurrentStore(1); + $this->storeManager->setCurrentStore($testStore1); - $testStore = $storeManager->getStore('test'); + /** @var Product $product*/ + $product = $this->productRepository->get('product1'); $productFilter = [ UrlRewrite::ENTITY_TYPE => 'product', @@ -154,7 +170,7 @@ public function testUrlKeyHasChangedInStoreviewContextWithPermanentRedirection() $product->setData('save_rewrites_history', true); $product->setUrlKey('new-url'); $product->setUrlPath('new-path'); - $product->save(); + $this->productRepository->save($product); $expected = [ [ @@ -162,21 +178,21 @@ public function testUrlKeyHasChangedInStoreviewContextWithPermanentRedirection() 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => 1, + 'store_id' => $testStore1->getId(), ], [ 'request_path' => "product-1.html", 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => $testStore->getId(), + 'store_id' => $testStore4->getId(), ], [ 'request_path' => "product-1.html", 'target_path' => "new-url.html", 'is_auto_generated' => 0, 'redirect_type' => 301, - 'store_id' => 1, + 'store_id' => $testStore1->getId(), ], ]; @@ -192,16 +208,13 @@ public function testUrlKeyHasChangedInStoreviewContextWithPermanentRedirection() */ public function testUrlKeyHasChangedInStoreviewContextWithoutPermanentRedirection() { - /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository*/ - $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); - /** @var \Magento\Catalog\Model\Product $product*/ - $product = $productRepository->get('product1'); + $testStore1 = $this->storeManager->getStore('default'); + $testStore4 = $this->storeManager->getStore('test'); - /** @var StoreManagerInterface $storeManager */ - $storeManager = $this->objectManager->get(StoreManagerInterface::class); - $storeManager->setCurrentStore(1); + $this->storeManager->setCurrentStore(1); - $testStore = $storeManager->getStore('test'); + /** @var Product $product*/ + $product = $this->productRepository->get('product1'); $productFilter = [ UrlRewrite::ENTITY_TYPE => 'product', @@ -210,7 +223,7 @@ public function testUrlKeyHasChangedInStoreviewContextWithoutPermanentRedirectio $product->setData('save_rewrites_history', false); $product->setUrlKey('new-url'); $product->setUrlPath('new-path'); - $product->save(); + $this->productRepository->save($product); $expected = [ [ @@ -218,17 +231,402 @@ public function testUrlKeyHasChangedInStoreviewContextWithoutPermanentRedirectio 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => 1, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore4->getId(), + ], + ]; + + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + } + + /** + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php + * @magentoAppIsolation enabled + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testAddAndRemoveProductFromWebsite() + { + $testStore1 = $this->storeManager->getStore('default'); + $testStore2 = $this->storeManager->getStore('fixture_second_store'); + $testStore3 = $this->storeManager->getStore('fixture_third_store'); + $testStore4 = $this->storeManager->getStore('test'); + + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + + /** @var Product $product*/ + $product = $this->productRepository->get('product1'); + + $productFilter = [ + UrlRewrite::ENTITY_TYPE => 'product', + ]; + + //Product in 1st website. Should result in being in 1st and 4th stores. + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore4->getId(), + ], + ]; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + + //Add product to websites corresponding to all 4 stores. + //Rewrites should be present for all stores. + $product->setWebsiteIds( + array_unique( + [ + $testStore1->getWebsiteId(), + $testStore2->getWebsiteId(), + $testStore3->getWebsiteId(), + $testStore4->getWebsiteId(), + ] + ) + ); + $this->productRepository->save($product); + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore2->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore3->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore4->getId(), + ] + ]; + + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + + //Remove product from stores 1 and 4 and leave assigned to stores 2 and 3. + $product->setWebsiteIds( + array_unique( + [ + $testStore2->getWebsiteId(), + $testStore3->getWebsiteId(), + ] + ) + ); + $this->productRepository->save($product); + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore2->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore3->getId(), + ], + ]; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + } + + /** + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testChangeVisibilityGlobalScope() + { + $testStore1 = $this->storeManager->getStore('default'); + $testStore2 = $this->storeManager->getStore('fixture_second_store'); + $testStore3 = $this->storeManager->getStore('fixture_third_store'); + $testStore4 = $this->storeManager->getStore('test'); + + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + + /** @var Product $product*/ + $product = $this->productRepository->get('product1'); + + $productFilter = [ + UrlRewrite::ENTITY_TYPE => 'product', + ]; + + //Product in 1st website. Should result in being in 1st and 4th stores. + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore4->getId(), + ] + ]; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + + //Set product to be not visible at global scope + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + $product->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE); + $this->productRepository->save($product); + $this->assertEmpty($this->getActualResults($productFilter)); + + //Add product to websites corresponding to all 4 stores. + //Rewrites should not be present as the product is hidden + //at the global scope. + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + $product->setWebsiteIds( + array_unique( + [ + $testStore1->getWebsiteId(), + $testStore2->getWebsiteId(), + $testStore3->getWebsiteId(), + $testStore4->getWebsiteId(), + ] + ) + ); + $this->productRepository->save($product); + $expected = []; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + + //Set product to be visible at global scope + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + $product->setVisibility(Visibility::VISIBILITY_BOTH); + $this->productRepository->save($product); + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore2->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore3->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore4->getId(), + ], + ]; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + } + + /** + * @magentoDataFixture Magento/Store/_files/second_website_with_two_stores.php + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_rewrite_multistore.php + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testChangeVisibilityLocalScope() + { + $testStore1 = $this->storeManager->getStore('default'); + $testStore2 = $this->storeManager->getStore('fixture_second_store'); + $testStore3 = $this->storeManager->getStore('fixture_third_store'); + $testStore4 = $this->storeManager->getStore('test'); + + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + + /** @var Product $product*/ + $product = $this->productRepository->get('product1'); + + $productFilter = [ + UrlRewrite::ENTITY_TYPE => 'product', + ]; + + //Product in 1st website. Should result in being in 1st and 4th stores. + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore4->getId(), + ], + ]; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + + //Set product to be not visible at store 4 scope + //Rewrite should only be present for store 1 + $this->storeManager->setCurrentStore($testStore4); + $product = $this->productRepository->get('product1'); + $product->setVisibility(Visibility::VISIBILITY_NOT_VISIBLE); + $this->productRepository->save($product); + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + ]; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + self::assertCount(count($expected), $actual); + + //Add product to websites corresponding to all 4 stores. + //Rewrites should be present for stores 1,2 and 3. + //No rewrites should be present for store 4 as that is not visible + //at local scope. + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + $product = $this->productRepository->get('product1'); + $product->getExtensionAttributes()->setWebsiteIds( + array_unique( + [ + $testStore1->getWebsiteId(), + $testStore2->getWebsiteId(), + $testStore3->getWebsiteId(), + $testStore4->getWebsiteId() + ], + ) + ); + $this->productRepository->save($product); + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore2->getId(), ], [ 'request_path' => "product-1.html", 'target_path' => "catalog/product/view/id/" . $product->getId(), 'is_auto_generated' => 1, 'redirect_type' => 0, - 'store_id' => $testStore->getId(), + 'store_id' => $testStore3->getId(), ], ]; + $actual = $this->getActualResults($productFilter); + foreach ($expected as $row) { + $this->assertContains($row, $actual); + } + //Set product to be visible at store 4 scope only + $this->storeManager->setCurrentStore($testStore4); + $product = $this->productRepository->get('product1'); + $product->setVisibility(Visibility::VISIBILITY_BOTH); + $this->productRepository->save($product); + $expected = [ + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore1->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore2->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore3->getId(), + ], + [ + 'request_path' => "product-1.html", + 'target_path' => "catalog/product/view/id/" . $product->getId(), + 'is_auto_generated' => 1, + 'redirect_type' => 0, + 'store_id' => $testStore4->getId(), + ], + ]; $actual = $this->getActualResults($productFilter); foreach ($expected as $row) { $this->assertContainsEquals($row, $actual); diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewritesTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewritesTest.php new file mode 100644 index 0000000000000..f958027f413e3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Plugin/Catalog/Model/Product/UpdateProductWebsiteUrlRewritesTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogUrlRewrite\Plugin\Catalog\Model\Product; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Action; +use Magento\Store\Api\StoreWebsiteRelationInterface; +use Magento\Store\Model\Website; +use Magento\Store\Model\WebsiteRepository; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * @magentoAppArea crontab + * @magentoDbIsolation disabled + */ +class UpdateProductWebsiteUrlRewritesTest extends TestCase +{ + /** + * @var Action + */ + private $action; + + /** + * @var StoreWebsiteRelationInterface + */ + private $storeWebsiteRelation; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + $objectManager = Bootstrap::getObjectManager(); + $this->action = $objectManager->get(Action::class); + $this->storeWebsiteRelation = $objectManager->get(StoreWebsiteRelationInterface::class); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_url_key.php + * @magentoDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php + */ + public function testUpdateUrlRewrites() + { + /** @var Website $website */ + $websiteRepository = Bootstrap::getObjectManager()->get(WebsiteRepository::class); + $website = $websiteRepository->get('test'); + $productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + $product = $productRepository->get('simple1', false, null, true); + $this->action->updateWebsites([$product->getId()], [$website->getId()], 'add'); + $storeIds = $this->storeWebsiteRelation->getStoreByWebsiteId($website->getId()); + + $this->assertStringContainsString( + $product->getUrlKey() . '.html', + $product->setStoreId(reset($storeIds))->getProductUrl() + ); + + $this->action->updateWebsites([$product->getId()], [$website->getId()], 'remove'); + $product->setRequestPath(''); + $url = $product->setStoreId(reset($storeIds))->getProductUrl(); + $this->assertStringNotContainsString( + $product->getUrlKey() . '.html', + $url + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrlTest.php b/dev/tests/integration/testsuite/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrlTest.php index a9ce1d4b181a9..6d635d01b2f48 100644 --- a/dev/tests/integration/testsuite/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrlTest.php +++ b/dev/tests/integration/testsuite/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrlTest.php @@ -65,8 +65,8 @@ protected function setUp(): void /** * Test switching stores with non-existent cms pages and then redirecting to the homepage * - * @magentoDataFixture Magento/UrlRewrite/_files/url_rewrite.php * @magentoDataFixture Magento/Catalog/_files/category_product.php + * @magentoDataFixture Magento/UrlRewrite/_files/url_rewrite.php * @magentoDbIsolation disabled * @magentoAppIsolation enabled * @return void From 9cae620c1648b48b01cce3dcc9fea06c9249a14a Mon Sep 17 00:00:00 2001 From: Elisei <brunoelisei@gmail.com> Date: Tue, 8 Dec 2020 13:19:04 -0300 Subject: [PATCH 213/346] Fixed #31211 --- app/code/Magento/Vault/i18n/en_US.csv | 1 + .../frontend/templates/customer_account/credit_card.phtml | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Vault/i18n/en_US.csv b/app/code/Magento/Vault/i18n/en_US.csv index f7ee19055563c..0c54d583198d1 100644 --- a/app/code/Magento/Vault/i18n/en_US.csv +++ b/app/code/Magento/Vault/i18n/en_US.csv @@ -13,3 +13,4 @@ Actions,Actions Delete,Delete "PayPal Account","PayPal Account" Cancel,Cancel +"Are you sure you want to delete this card: %1?","Are you sure you want to delete this card: %1?" \ No newline at end of file diff --git a/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml b/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml index 7be7946fff1bf..a2439898799cd 100644 --- a/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml +++ b/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml @@ -43,9 +43,7 @@ $ccNumberView = $block->escapeHtml($block->getNumberLast4Digits()); "modalClass": "my-credit-cards-popup", "toggleEvent": "click", "title": "<?= $block->escapeHtml(__('Delete')) ?>", - "content": "Are you sure you want to delete this card: <?= - /* @noEscape */ $ccNumberView - ?>?" + "content": "<?= $block->escapeHtml(__('Are you sure you want to delete this card: %1?', /* @noEscape */ $ccNumberView)) ?>" } }'> <span><?= $block->escapeHtml(__('Delete')) ?></span> From 5602710848756d2918837e1a81c9f77c03a7ec2a Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Tue, 8 Dec 2020 11:24:53 -0600 Subject: [PATCH 214/346] MC-38913: Associate to Website Functionality - Fix customer associated website should not be editable in customer grid --- .../AdminCustomerGridInlineEditorSection.xml | 3 + ...minChangeCustomerAssociatedWebsiteTest.xml | 85 +++++++++++++++++++ .../ui_component/customer_listing.xml | 3 - 3 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml index d010844cfffcf..f074217224372 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml @@ -11,5 +11,8 @@ <section name="AdminCustomerGridInlineEditorSection"> <element name="customerGenderEditor" type="select" selector="tr.data-grid-editable-row:not([style*='display: none']) [name='gender']"/> <element name="saveInGrid" type="button" selector="tr.data-grid-editable-row-actions button.action-primary" timeout="30"/> + <element name="customerEmailEditor" type="select" selector="tr.data-grid-editable-row:not([style*='display: none']) input[name='email']"/> + <element name="customerWebsiteEditor" type="select" selector="tr.data-grid-editable-row:not([style*='display: none']) select[name='website_id']"/> + <element name="cellContent" type="select" selector="//tr[@class='data-grid-editable-row' and not(contains(@style,'display:none'))]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{col}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml new file mode 100644 index 0000000000000..2f4898921d0b6 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminChangeCustomerAssociatedWebsiteTest"> + <annotations> + <features value="Customer"/> + <title value="Admin should not be able to change customer assigned website ID"/> + <description value="Admin should not be able to change customer assigned website ID"/> + <severity value="AVERAGE"/> + <useCaseId value="MC-38913"/> + <testCaseId value="MC-39764"/> + <stories value="Customer Edit"/> + <group value="customer"/> + </annotations> + + <before> + <!--Login to admin--> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <!--Create second website--> + <actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createWebsite"> + <argument name="newWebsiteName" value="{{NewWebSiteData.name}}"/> + <argument name="websiteCode" value="{{NewWebSiteData.code}}"/> + </actionGroup> + <!--Create store group and associate it to second website--> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createNewStore"> + <argument name="website" value="{{NewWebSiteData.name}}"/> + <argument name="storeGroupName" value="{{NewStoreData.name}}"/> + <argument name="storeGroupCode" value="{{NewStoreData.code}}"/> + </actionGroup> + <!--Create store view and associate it to second store group--> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createCustomStoreView"> + <argument name="StoreGroup" value="NewStoreData"/> + <argument name="customStore" value="NewStoreViewData"/> + </actionGroup> + <!--Create customer--> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + </before> + <after> + <!--Delete customer--> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <!--Reset customer grid filter--> + <actionGroup ref="AdminOpenCustomersGridActionGroup" stepKey="navigateToCustomersPage"/> + <actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearCustomersGridFilter"/> + <!--Delete custom website--> + <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteWebsite"> + <argument name="websiteName" value="{{NewWebSiteData.name}}"/> + </actionGroup> + <!--Logout from admin--> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> + </after> + <!--Open customer grid--> + <actionGroup ref="AdminOpenCustomersGridActionGroup" stepKey="navigateToCustomersPage"/> + <!--Filter customers grid by email--> + <actionGroup ref="AdminFilterCustomerGridByEmail" stepKey="filterCustomer"> + <argument name="email" value="$createCustomer.email$"/> + </actionGroup> + <!--Click on customer row to open inline editor--> + <click selector="{{AdminDataGridTableSection.rowTemplate($createCustomer.email$)}}" stepKey="clickCustomersGridRow"/> + <!--Wait for inline editor to open--> + <waitForElementVisible selector="{{AdminCustomerGridInlineEditorSection.customerEmailEditor}}" stepKey="waitForEditor"/> + <!--Assert that website is not editable--> + <dontSeeElement selector="{{AdminCustomerGridInlineEditorSection.customerWebsiteEditor}}" stepKey="dontSeeWebsiteEditor"/> + <!--Assert that "Main Website" is displayed in website cell--> + <see selector="{{AdminCustomerGridInlineEditorSection.cellContent('Web Site')}}" userInput="{{_defaultWebsite.name}}" stepKey="assertThatMainWebsiteIsDisplayedInWebsiteCell"/> + <!--Open customer edit page--> + <actionGroup ref="AdminOpenCustomerEditPageActionGroup" stepKey="openCustomerEditPage"> + <argument name="customerId" value="$createCustomer.id$"/> + </actionGroup> + <!--Navigate to "Account Information" tab--> + <actionGroup ref="AdminOpenAccountInformationTabFromCustomerEditPageActionGroup" stepKey="openAccountInformationEditPage"/> + <!--Assert that "Main Website" is selected in website selector--> + <seeOptionIsSelected selector="{{AdminCustomerAccountInformationSection.associateToWebsite}}" userInput="{{_defaultWebsite.name}}" stepKey="assertThatMainWebsiteIsSelected"/> + <!--Assert that website selector is disabled--> + <assertElementContainsAttribute stepKey="assertThatWebsiteSelectorIsDisabled"> + <expectedResult selector="{{AdminCustomerAccountInformationSection.associateToWebsite}}" attribute="disabled" type="string"/> + </assertElementContainsAttribute> + </test> +</tests> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml index 97ae9a9953eb6..b60506ab856c4 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml @@ -190,9 +190,6 @@ <column name="website_id" class="Magento\Customer\Ui\Component\Listing\Column\Websites" component="Magento_Ui/js/grid/columns/select" sortOrder="110"> <settings> <filter>select</filter> - <editor> - <editorType>select</editorType> - </editor> <dataType>select</dataType> <label translate="true">Web Site</label> </settings> From 9ce704accb9fc4d732abcc77d0629879d31aa461 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <dhorytskyi@magento.com> Date: Tue, 8 Dec 2020 20:28:37 -0600 Subject: [PATCH 215/346] MC-39747: catalog:images:resize stops when cannot process image --- .../MediaStorage/Service/ImageResize.php | 11 +++- .../Test/Unit/Service/ImageResizeTest.php | 62 ++++++++++++++++--- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/MediaStorage/Service/ImageResize.php b/app/code/Magento/MediaStorage/Service/ImageResize.php index d5ce1a7e20f98..9b0adcd161339 100644 --- a/app/code/Magento/MediaStorage/Service/ImageResize.php +++ b/app/code/Magento/MediaStorage/Service/ImageResize.php @@ -195,14 +195,18 @@ public function resizeFromThemes(array $themes = null): Generator $this->fileStorageDatabase->saveFileToFilesystem($mediastoragefilename); } if ($this->mediaDirectory->isFile($originalImagePath)) { - foreach ($viewImages as $viewImage) { - $this->resize($viewImage, $originalImagePath, $originalImageName); + try { + foreach ($viewImages as $viewImage) { + $this->resize($viewImage, $originalImagePath, $originalImageName); + } + } catch (\Exception $e) { + $error = $e->getMessage(); } } else { $error = __('Cannot resize image "%1" - original image not found', $originalImagePath); } - yield ['filename' => $originalImageName, 'error' => $error] => $count; + yield ['filename' => $originalImageName, 'error' => (string) $error] => $count; } } @@ -276,6 +280,7 @@ private function getUniqueImageIndex(array $imageData): string * @param string $originalImagePath * @param array $imageParams * @return Image + * @throws \InvalidArgumentException */ private function makeImage(string $originalImagePath, array $imageParams): Image { diff --git a/app/code/Magento/MediaStorage/Test/Unit/Service/ImageResizeTest.php b/app/code/Magento/MediaStorage/Test/Unit/Service/ImageResizeTest.php index b8c4aded8a047..5df2269f8f80e 100644 --- a/app/code/Magento/MediaStorage/Test/Unit/Service/ImageResizeTest.php +++ b/app/code/Magento/MediaStorage/Test/Unit/Service/ImageResizeTest.php @@ -60,11 +60,6 @@ class ImageResizeTest extends TestCase */ protected $imageFactoryMock; - /** - * @var Image|MockObject - */ - protected $imageMock; - /** * @var ParamsBuilder|MockObject */ @@ -141,7 +136,6 @@ protected function setUp(): void $this->appStateMock = $this->createMock(State::class); $this->imageConfigMock = $this->createMock(MediaConfig::class); $this->productImageMock = $this->createMock(ProductImage::class); - $this->imageMock = $this->createMock(Image::class); $this->imageFactoryMock = $this->createMock(ImageFactory::class); $this->paramsBuilderMock = $this->createMock(ParamsBuilder::class); $this->viewMock = $this->createMock(View::class); @@ -164,9 +158,6 @@ protected function setUp(): void ->with(DirectoryList::MEDIA) ->willReturn($this->mediaDirectoryMock); - $this->imageFactoryMock->expects($this->any()) - ->method('create') - ->willReturn($this->imageMock); $this->assetImageMock->expects($this->any()) ->method('getPath') ->willReturn($this->testfilepath); @@ -256,6 +247,11 @@ public function testResizeFromThemesMediaStorageDatabase() ->method('fileExists') ->willReturn(false); + $imageMock = $this->createMock(Image::class); + $this->imageFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($imageMock); + $this->productImageMock->expects($this->any()) ->method('getCountUsedProductImages') ->willReturn(1); @@ -284,6 +280,49 @@ function () { $generator = $this->service->resizeFromThemes(['test-theme']); while ($generator->valid()) { + $resizeInfo = $generator->key(); + $this->assertEquals('image.jpg', $resizeInfo['filename']); + $this->assertEmpty($resizeInfo['error']); + $generator->next(); + } + } + + public function testResizeFromThemesUnsupportedImage() + { + $this->databaseMock->expects($this->any()) + ->method('checkDbUsage') + ->willReturn(true); + $this->databaseMock->expects($this->any()) + ->method('fileExists') + ->willReturn(false); + + $this->imageFactoryMock->expects($this->once()) + ->method('create') + ->willThrowException(new \InvalidArgumentException('Unsupported image format.')); + + $this->productImageMock->expects($this->any()) + ->method('getCountUsedProductImages') + ->willReturn(1); + $this->productImageMock->expects($this->any()) + ->method('getUsedProductImages') + ->willReturnCallback( + function () { + $data = [[ 'filepath' => $this->testfilename ]]; + foreach ($data as $e) { + yield $e; + } + } + ); + + $this->mediaDirectoryMock->expects($this->any()) + ->method('isFile') + ->with($this->testfilepath) + ->willReturn(true); + + $generator = $this->service->resizeFromThemes(['test-theme']); + while ($generator->valid()) { + $resizeInfo = $generator->key(); + $this->assertEquals('Unsupported image format.', $resizeInfo['error']); $generator->next(); } } @@ -297,6 +336,11 @@ public function testResizeFromImageNameMediaStorageDatabase() ->method('fileExists') ->willReturn(false); + $imageMock = $this->createMock(Image::class); + $this->imageFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($imageMock); + $this->mediaDirectoryMock->expects($this->any()) ->method('isFile') ->with($this->testfilepath) From 69c26af51b38754144eedf1ad73b44e479f4f29a Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <dhorytskyi@magento.com> Date: Tue, 8 Dec 2020 21:04:52 -0600 Subject: [PATCH 216/346] MC-39776: JS error on Create New Customer Account page --- .../templates/shopping-assistance.phtml | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/LoginAsCustomerAssistance/view/frontend/templates/shopping-assistance.phtml b/app/code/Magento/LoginAsCustomerAssistance/view/frontend/templates/shopping-assistance.phtml index 7765975863485..5551ea1baba70 100644 --- a/app/code/Magento/LoginAsCustomerAssistance/view/frontend/templates/shopping-assistance.phtml +++ b/app/code/Magento/LoginAsCustomerAssistance/view/frontend/templates/shopping-assistance.phtml @@ -11,20 +11,18 @@ use Magento\LoginAsCustomerAssistance\ViewModel\ShoppingAssistanceViewModel; /** @var Escaper $escaper */ /** @var ShoppingAssistanceViewModel $viewModel */ $viewModel = $block->getViewModel(); -?> -<script type="text/x-magento-init"> -{ - ".form-create-account, .form-edit-account": { - "Magento_LoginAsCustomerAssistance/js/opt-in": { - "allowAccess": "<?= /* @noEscape */ IsAssistanceEnabledInterface::ALLOWED ?>", - "denyAccess": "<?= /* @noEscape */ IsAssistanceEnabledInterface::DENIED ?>" +if ($viewModel->isLoginAsCustomerEnabled()): ?> + <script type="text/x-magento-init"> + { + ".form-create-account, .form-edit-account": { + "Magento_LoginAsCustomerAssistance/js/opt-in": { + "allowAccess": "<?= /* @noEscape */ IsAssistanceEnabledInterface::ALLOWED ?>", + "denyAccess": "<?= /* @noEscape */ IsAssistanceEnabledInterface::DENIED ?>" + } } } -} -</script> - -<?php if ($viewModel->isLoginAsCustomerEnabled()): ?> + </script> <div class="field choice"> <input type="checkbox" name="assistance_allowed_checkbox" From 8b5549cc4e92c64720b6e7b802eca7b9512229ba Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Wed, 9 Dec 2020 00:53:21 -0600 Subject: [PATCH 217/346] MC-39353: Incorrect Quantity Shipped Displayed on order detail page on the front - MFTF test and the solution --- .../StorefrontCustomerOrderShipmentPage.xml | 14 +++ ...ontOrderShipmentsQtyShippedActionGroup.xml | 24 ++++ .../StorefrontSalesOrderShipmentSection.xml | 14 +++ ...ifyOrderShipmentForDecimalQuantityTest.xml | 104 ++++++++++++++++++ .../shipment/items/renderer/default.phtml | 2 +- 5 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderShipmentPage.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AssertStorefrontOrderShipmentsQtyShippedActionGroup.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/StorefrontSalesOrderShipmentSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/StorefrontVerifyOrderShipmentForDecimalQuantityTest.xml diff --git a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderShipmentPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderShipmentPage.xml new file mode 100644 index 0000000000000..da41e6ada79a0 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderShipmentPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="StorefrontCustomerOrderShipmentPage" url="sales/order/shipment/order_id/{{var1}}" area="storefront" module="Magento_Customer" parameterized="true"> + <section name="StorefrontCustomerOrderSection"/> + </page> +</pages> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AssertStorefrontOrderShipmentsQtyShippedActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AssertStorefrontOrderShipmentsQtyShippedActionGroup.xml new file mode 100644 index 0000000000000..0c3544f8944ed --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AssertStorefrontOrderShipmentsQtyShippedActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertStorefrontOrderShipmentsQtyShippedActionGroup"> + <annotations> + <description>Verify Customer Order Shipments Qty Shipped</description> + </annotations> + <arguments> + <argument name="expectedQtyShipped" type="string" defaultValue="0"/> + </arguments> + <grabTextFrom selector="{{StorefrontSalesOrderShipmentSection.salesOrderQtyShipped}}" stepKey="grabSalesOrderQtyShipped"/> + <assertEquals stepKey="assertOrderQtyShipped"> + <actualResult type="string">$grabSalesOrderQtyShipped</actualResult> + <expectedResult type="string">{{expectedQtyShipped}}</expectedResult> + </assertEquals> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/StorefrontSalesOrderShipmentSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontSalesOrderShipmentSection.xml new file mode 100644 index 0000000000000..e2e814efb9f02 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/StorefrontSalesOrderShipmentSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontSalesOrderShipmentSection"> + <element name="salesOrderQtyShipped" type="text" selector="//td[@data-th='Qty Shipped']"/> + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/StorefrontVerifyOrderShipmentForDecimalQuantityTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontVerifyOrderShipmentForDecimalQuantityTest.xml new file mode 100644 index 0000000000000..b086074132e85 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/StorefrontVerifyOrderShipmentForDecimalQuantityTest.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontVerifyOrderShipmentForDecimalQuantityTest"> + <annotations> + <title value="Incorrect Quantity Shipped Displayed on order detail page on the front"/> + <stories value="Verify shipment quantity for decimal quantity at frontend order shipment tab"/> + <description value="Verify shipment quantity for decimal quantity at frontend order shipment tab"/> + <features value="Sales"/> + <testCaseId value="MC-39777"/> + <useCaseId value="MC-39353"/> + <severity value="MAJOR"/> + <group value="Sales"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createSimpleCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createSimpleCategory"/> + </createData> + <createData entity="Simple_US_Customer" stepKey="createSimpleUsCustomer"> + <field key="group_id">1</field> + </createData> + </before> + <after> + <!--Clear Filters--> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="ClearFiltersAfter"/> + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearOrderListingFilters"/> + <deleteData createDataKey="createSimpleCategory" stepKey="deletePreReqCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deletePreReqSimpleProduct"/> + <!--Logout from customer account--> + <amOnPage url="{{StorefrontCustomerLogoutPage.url}}" stepKey="logoutCustomerOne"/> + <waitForPageLoad stepKey="waitLogoutCustomerOne"/> + <deleteData createDataKey="createSimpleUsCustomer" stepKey="deleteCustomer"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <!--Step1. Login as admin. Go to Catalog > Products page. Filtering *prod1*. Open *prod1* to edit--> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin" /> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="filterGroupedProductOptions"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <!-- Step2. Update product Advanced Inventory Setting. + Set *Qty Uses Decimals* to *Yes* and *Enable Qty Increments* to *Yes* and *Qty Increments* to *2.14*. --> + <actionGroup ref="OpenProductForEditByClickingRowXColumnYInProductGridActionGroup" stepKey="openProduct"/> + <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickOnAdvancedInventoryLink"/> + <actionGroup ref="AdminSetQtyUsesDecimalsConfigActionGroup" stepKey="setQtyUsesDecimalsConfig"> + <argument name="value" value="Yes"/> + </actionGroup> + <actionGroup ref="AdminSetEnableQtyIncrementsActionGroup" stepKey="setEnableQtyIncrements"> + <argument name="value" value="Yes"/> + </actionGroup> + <actionGroup ref="AdminSetQtyIncrementsForProductActionGroup" stepKey="setQtyIncrementsValue"> + <argument name="qty" value="2.14"/> + </actionGroup> + <actionGroup ref="AdminSetMinAllowedQtyForProductActionGroup" stepKey="fillMiniAllowedQty"> + <argument name="qty" value="2.14"/> + </actionGroup> + <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickOnDoneButton"/> + + <!--Step3. Save the product--> + <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="clickOnSaveButton"/> + <!--Step4. Open *Customer view* (Go to *Store Front*). Open *prod1* page (Find via search and click on product name) --> + <!--Step5. Log in to Storefront as Customer--> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="signUpNewUser"> + <argument name="Customer" value="$$createSimpleUsCustomer$$"/> + </actionGroup> + <!--Step6. Go to product page--> + <amOnPage url="$$createSimpleProduct.custom_attributes[url_key]$$.html" stepKey="navigateToSimpleProductPage"/> + <waitForPageLoad stepKey="waitForCatalogPageLoad"/> + <!--Step7. Add Product to Shopping Cart--> + <actionGroup ref="AddToCartFromStorefrontProductPageActionGroup" stepKey="addToCartFromStorefrontProductPage"> + <argument name="productName" value="$$createSimpleProduct.name$$"/> + </actionGroup> + + <!--Step8. Navigate to checkout--> + <actionGroup ref="StorefrontOpenCheckoutPageActionGroup" stepKey="openCheckoutPage"/> + <!--Step9. Click next button to open payment section--> + <actionGroup ref="StorefrontCheckoutClickNextButtonActionGroup" stepKey="clickNext"/> + <!--Step10. Click place order--> + <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="placeOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="grabOrderNumber"/> + <!--Step11. Go to admin Order page for newly created order--> + <actionGroup ref="OpenOrderByIdActionGroup" stepKey="filterOrdersGridById"> + <argument name="orderId" value="{$grabOrderNumber}"/> + </actionGroup> + + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction"/> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment"/> + + <actionGroup ref="StorefrontNavigateToCustomerOrdersHistoryPageActionGroup" stepKey="goToOrderHistoryPage"/> + <!--Step12. Go to Customer Order Shipment Page and Checking the correctness of displayed Qty Shipped --> + <amOnPage url="{{StorefrontCustomerOrderShipmentPage.url({$grabOrderNumber})}}" stepKey="amOnOrderShipmentPage"/> + <waitForPageLoad time="30" stepKey="waitForOrderShipmentsPageLoad"/> + <actionGroup ref="AssertStorefrontOrderShipmentsQtyShippedActionGroup" stepKey="verifyAssertOrderShipments"> + <argument name="expectedQtyShipped" value="2.14"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Sales/view/frontend/templates/order/shipment/items/renderer/default.phtml b/app/code/Magento/Sales/view/frontend/templates/order/shipment/items/renderer/default.phtml index 6c7567a8cd14b..d2caa1a2ce935 100644 --- a/app/code/Magento/Sales/view/frontend/templates/order/shipment/items/renderer/default.phtml +++ b/app/code/Magento/Sales/view/frontend/templates/order/shipment/items/renderer/default.phtml @@ -42,5 +42,5 @@ <td class="col sku" data-th="<?= $block->escapeHtml(__('SKU')) ?>"> <?= /* @noEscape */ $block->prepareSku($block->getSku()) ?> </td> - <td class="col qty" data-th="<?= $block->escapeHtml(__('Qty Shipped')) ?>"><?= (int) $_item->getQty() ?></td> + <td class="col qty" data-th="<?= $block->escapeHtml(__('Qty Shipped')) ?>"><?= (float) $_item->getQty() ?></td> </tr> From 780419693249f6fae17d4702cd203c2ab4aae61a Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Wed, 9 Dec 2020 11:35:17 +0200 Subject: [PATCH 218/346] fix mftf stepKeys order --- .../AdminApplyTierPriceToProductWithPercentageDiscountTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml index 594eb320e439a..143fa6657cd3b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml @@ -43,8 +43,8 @@ <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="scrollToTopOfPage"/> <actionGroup ref="AdminProductFormOpenAdvancedPricingDialogActionGroup" stepKey="clickOnAdvancedPricingButton"/> - <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAndpercente"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForCustomerGroupPriceAddButton"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAndpercente"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="fillProductTierPriceQtyInput"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectProductTierPriceValueType"/> From fe6298b0ae448de156a317545463e773a2166258 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 9 Dec 2020 12:24:53 +0200 Subject: [PATCH 219/346] refactored AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest --- ...AssertManageStockOnEditPageActionGroup.xml | 22 +++ ...AssertProductInfoOnEditPageActionGroup.xml | 32 ++++ ...ProductIsAssignedToCategoryActionGroup.xml | 22 +++ ...ssignTwoCategoriesToProductActionGroup.xml | 26 +++ .../AdminFillMainProductFormActionGroup.xml | 21 +++ ...uctStockStatusOnProductPageActionGroup.xml | 20 +++ .../AdminProductFormSection.xml | 1 + ...WithRegularPriceInStockEnabledFlatTest.xml | 166 ++++++++---------- 8 files changed, 218 insertions(+), 92 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductIsAssignedToCategoryActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssignTwoCategoriesToProductActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminFillMainProductFormActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml new file mode 100644 index 0000000000000..f9c9098732476 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAssertManageStockOnEditPageActionGroup"> + <annotations> + <description>Check if manageStock value is correct (the Product Edit page should be opened in Admin prior this check).</description> + </annotations> + <arguments> + <argument name="manageStock" type="string"/> + </arguments> + + <see selector="{{AdminProductFormAdvancedInventorySection.manageStock}}" userInput="{{manageStock}}" stepKey="seeManageStock"/> + + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml new file mode 100644 index 0000000000000..b70c7a4d62dcf --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAssertProductInfoOnEditPageActionGroup"> + <annotations> + <description>Validates next fields on the Edit Product Page: name, sku, price, quantity, stock status, tax class, weight, weigh select, visibility, url key</description> + </annotations> + <arguments> + <argument name="product" type="entity"/> + </arguments> + <waitForPageLoad stepKey="waitForProductToLoad"/> + <seeInField selector="{{AdminProductFormSection.productName}}" userInput="{{product.name}}" stepKey="seeProductName"/> + <seeInField selector="{{AdminProductFormSection.productSku}}" userInput="{{product.sku}}" stepKey="seeProductSku"/> + <seeInField selector="{{AdminProductFormSection.productPrice}}" userInput="{{product.price}}" stepKey="seeProductPrice"/> + <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{product.quantity}}" stepKey="seeProductQuantity"/> + <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{product.status}}" stepKey="seeProductStockStatus"/> + <seeInField selector="{{AdminProductFormSection.productTaxClass}}" userInput="{{product.productTaxClass}}" stepKey="seeProductTaxClass"/> + <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{product.weight}}" stepKey="seeSimpleProductWeight"/> + <seeInField selector="{{AdminProductFormSection.productWeightSelect}}" userInput="{{product.weightSelect}}" stepKey="seeSimpleProductWeightSelect"/> + <seeInField selector="{{AdminProductFormSection.visibility}}" userInput="{{product.visibility}}" stepKey="seeVisibility"/> + <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> + <seeInField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{product.urlKey}}" stepKey="seeUrlKey"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductIsAssignedToCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductIsAssignedToCategoryActionGroup.xml new file mode 100644 index 0000000000000..b33e319adc1f4 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductIsAssignedToCategoryActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAssertProductIsAssignedToCategoryActionGroup"> + <annotations> + <description>Checks if product is assigned to category (the Product Edit page should be opened in Admin prior this check).</description> + </annotations> + <arguments> + <argument name="categoryName" type="string"/> + </arguments> + + <seeElement selector="{{AdminProductFormSection.categories(categoryName)}}" stepKey="seeCategoryName"/> + + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssignTwoCategoriesToProductActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssignTwoCategoriesToProductActionGroup.xml new file mode 100644 index 0000000000000..06b4b68630326 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssignTwoCategoriesToProductActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAssignTwoCategoriesToProductActionGroup" extends="AdminAssignCategoryToProductAndSaveActionGroup"> + <annotations> + <description>Extends AdminAssignCategoryToProductAndSaveActionGroup + assigns the second category and prevents product saving (the Product Edit page should be opened in Admin prior this check).</description> + </annotations> + <arguments> + <argument name="categoryTwoName" type="string"/> + </arguments> + <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="openDropDown2" after="waitForApplyCategory"/> + <checkOption selector="{{AdminProductFormSection.selectCategory(categoryTwoName)}}" stepKey="selectCategoryTwo"/> + <click selector="{{AdminProductFormSection.done}}" stepKey="clickDone2"/> + <waitForPageLoad stepKey="waitForApplyCategoryTwo"/> + <remove keyForRemoval="clickSave"/> + <remove keyForRemoval="waitForSavingProduct"/> + <remove keyForRemoval="seeSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminFillMainProductFormActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminFillMainProductFormActionGroup.xml new file mode 100644 index 0000000000000..c5818a4eea51b --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminFillMainProductFormActionGroup.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFillMainProductFormActionGroup" extends="FillMainProductFormActionGroup"> + <annotations> + <description>Extends FillMainProductFormActionGroup with filling the next fields: Tax Class, Visibility, SEO->URL </description> + </annotations> + + <selectOption selector="{{AdminProductFormSection.productTaxClass}}" userInput="{{product.productTaxClass}}" stepKey="selectProductTaxClass"/> + <selectOption selector="{{AdminProductFormSection.visibility}}" userInput="{{product.visibility}}" stepKey="selectVisibility"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection"/> + <fillField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{product.urlKey}}" stepKey="fillUrlKey"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml new file mode 100644 index 0000000000000..356302ef26b9c --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontAssertProductStockStatusOnProductPageActionGroup"> + <annotations> + <description>Validate that the provided Product Stock Status is present and correct (the Product Detail page should be opened on Storefront prior this check)</description> + </annotations> + <arguments> + <argument name="productStockStatus" type="string"/> + </arguments> + + <see selector="{{StorefrontProductInfoMainSection.productStockStatus}}" userInput="{{productStockStatus}}" stepKey="seeProductStockStatus"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml index 1ca051e2f6669..d70c48f2b00e3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml @@ -77,5 +77,6 @@ <element name="newAddedAttribute" type="text" selector="//fieldset[@class='admin__fieldset']//div[contains(@data-index,'{{attributeCode}}')]" parameterized="true"/> <element name="newCategoryButton" type="button" selector="button[data-index='create_category_button']" timeout="30"/> <element name="footerBlock" type="block" selector="//footer"/> + <element name="categories" type="text" selector="//*[@class='admin__action-multiselect-crumb']/span[contains(text(), '{{categoryName}}')]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml index aa1b1ae702914..4bf15199f0db5 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml @@ -6,7 +6,7 @@ */ --> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest"> <annotations> @@ -37,104 +37,86 @@ <magentoCLI stepKey="unsetFlatCatalogProduct" command="config:set catalog/frontend/flat_catalog_product 0"/> </after> - <!-- Search default simple product in the grid page --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openProductPage"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> - <!-- Update simple product with regular price --> - <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="fillSimpleProductName"/> - <fillField selector="{{AdminProductFormSection.productSku}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="fillSimpleProductSku"/> - <fillField selector="{{AdminProductFormSection.productPrice}}" userInput="{{simpleProductEnabledFlat.price}}" stepKey="fillSimpleProductPrice"/> - <selectOption selector="{{AdminProductFormSection.productTaxClass}}" userInput="{{simpleProductEnabledFlat.productTaxClass}}" stepKey="selectProductTaxClass"/> - <fillField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductEnabledFlat.quantity}}" stepKey="fillSimpleProductQuantity"/> <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickAdvancedInventoryLink"/> - <conditionalClick selector="{{AdminProductFormAdvancedInventorySection.useConfigSettings}}" dependentSelector="{{AdminProductFormAdvancedInventorySection.useConfigSettings}}" visible="true" stepKey="checkUseConfigSettingsCheckBox"/> - <selectOption selector="{{AdminProductFormAdvancedInventorySection.manageStock}}" userInput="No" stepKey="selectManageStock"/> + <actionGroup ref="AdminSetManageStockConfigActionGroup" stepKey="setManageStockConfig"> + <argument name="value" value="No"/> + </actionGroup> <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButtonOnAdvancedInventorySection"/> - <selectOption selector="{{AdminProductFormSection.stockStatus}}" userInput="{{simpleProductEnabledFlat.status}}" stepKey="selectStockStatusInStock"/> - <fillField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductEnabledFlat.weight}}" stepKey="fillSimpleProductWeight"/> - <selectOption selector="{{AdminProductFormSection.productWeightSelect}}" userInput="{{simpleProductEnabledFlat.weightSelect}}" stepKey="selectProductWeight"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDown"/> - <fillField selector="{{AdminProductFormSection.searchCategory}}" userInput="$$initialCategoryEntity.name$$" stepKey="fillSearchForInitialCategory" /> - <waitForPageLoad stepKey="waitForCategory1"/> - <click selector="{{AdminProductFormSection.selectCategory($$initialCategoryEntity.name$$)}}" stepKey="unselectInitialCategory"/> - <fillField selector="{{AdminProductFormSection.searchCategory}}" userInput="$$categoryEntity.name$$" stepKey="fillSearchCategory" /> - <waitForPageLoad stepKey="waitForCategory2"/> - <click selector="{{AdminProductFormSection.selectCategory($$categoryEntity.name$$)}}" stepKey="clickOnCategory"/> - <actionGroup ref="AdminSubmitCategoriesPopupActionGroup" stepKey="clickOnDoneAdvancedCategorySelect"/> - <selectOption selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductEnabledFlat.visibility}}" stepKey="selectVisibility"/> - <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection"/> - <fillField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{simpleProductEnabledFlat.urlKey}}" stepKey="fillUrlKey"/> - <scrollToTopOfPage stepKey="scrollToTopOfAdminProductFormSection"/> + + <actionGroup ref="AdminAssignTwoCategoriesToProductActionGroup" stepKey="assignCategories"> + <argument name="categoryName" value="$$initialCategoryEntity.name$$"/> + <argument name="categoryTwoName" value="$$categoryEntity.name$$"/> + </actionGroup> + + <actionGroup ref="AdminFillMainProductFormActionGroup" stepKey="fillSimpleProductInfo"> + <argument name="product" value="simpleProductEnabledFlat"/> + </actionGroup> + <actionGroup ref="AdminProductFormSaveButtonClickActionGroup" stepKey="clickSaveButton"/> - <!-- Verify customer see success message --> - <see selector="{{AdminProductFormSection.successMessage}}" userInput="You saved the product." stepKey="seeAssertSimpleProductSaveSuccessMessage"/> - - <!-- Search updated simple product(from above step) in the grid page --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPageToSearchUpdatedSimpleProduct"/> - <conditionalClick selector="{{AdminProductGridFilterSection.clearAll}}" dependentSelector="{{AdminProductGridFilterSection.clearAll}}" visible="true" stepKey="clickClearAll"/> - <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="clickFiltersButton"/> - <fillField selector="{{AdminProductGridFilterSection.nameFilter}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="fillSimpleProductNameInNameFilter"/> - <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="fillProductSku"/> - <click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToVerifyUpdatedSimpleProductVisibleInGrid"/> - <waitForPageLoad stepKey="waitUntilSimpleProductPageIsOpened"/> - - <!-- Verify customer see updated simple product in the product form page --> - <seeInField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductName"/> - <seeInField selector="{{AdminProductFormSection.productSku}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="seeSimpleProductSku"/> - <seeInField selector="{{AdminProductFormSection.productPrice}}" userInput="{{simpleProductEnabledFlat.price}}" stepKey="seeSimpleProductPrice"/> - <seeInField selector="{{AdminProductFormSection.productTaxClass}}" userInput="{{simpleProductEnabledFlat.productTaxClass}}" stepKey="seeProductTaxClass"/> - <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductEnabledFlat.quantity}}" stepKey="seeSimpleProductQuantity"/> - <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickTheAdvancedInventoryLink"/> - <see selector="{{AdminProductFormAdvancedInventorySection.manageStock}}" userInput="No" stepKey="seeManageStock"/> - <click selector="{{AdminProductFormAdvancedInventorySection.advancedInventoryCloseButton}}" stepKey="clickDoneButtonOnAdvancedInventory"/> - <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductEnabledFlat.status}}" stepKey="seeSimpleProductStockStatus"/> - <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductEnabledFlat.weight}}" stepKey="seeSimpleProductWeight"/> - <seeInField selector="{{AdminProductFormSection.productWeightSelect}}" userInput="{{simpleProductEnabledFlat.weightSelect}}" stepKey="seeSimpleProductWeightSelect"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="seeSelectedCategories" /> - <seeInField selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductEnabledFlat.visibility}}" stepKey="seeVisibility"/> - <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> - <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> - <seeInField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{simpleProductEnabledFlat.urlKey}}" stepKey="seeUrlKey"/> - - <!--Verify customer see updated simple product link on category page --> - <amOnPage url="{{StorefrontCategoryPage.url($$categoryEntity.name$$)}}" stepKey="openCategoryPage"/> - <waitForPageLoad stepKey="waitForCategoryPageLoad"/> - <see selector="{{StorefrontCategoryMainSection.productLink}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductNameOnCategoryPage"/> - - <!-- Verify customer see updated simple product (from the above step) on the storefront page --> - <amOnPage url="{{StorefrontProductPage.url(simpleProductEnabledFlat.urlKey)}}" stepKey="goToProductPage"/> - <waitForPageLoad stepKey="waitForStorefrontProductPageLoad"/> - <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductNameOnStoreFrontPage"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="{{simpleProductEnabledFlat.price}}" stepKey="seeSimpleProductPriceOnStoreFrontPage"/> - <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeSimpleProductSkuOnStoreFrontPage"> + <see selector="{{AdminProductFormSection.successMessage}}" userInput="You saved the product." stepKey="seeSimpleProductSavedSuccessMessage"/> + + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage1"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openProductPage1"> + <argument name="product" value="simpleProductEnabledFlat"/> + </actionGroup> + + <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickTheAdvancedInventoryLink1"/> + <actionGroup ref="AdminAssertManageStockOnEditPageActionGroup" stepKey="assertManageStock1"> + <argument name="manageStock" value="No"/> + </actionGroup> + <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButtonOnAdvancedInventorySection1"/> + + <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToInitialCategory"> + <argument name="categoryName" value="$$initialCategoryEntity.name$$"/> + </actionGroup> + + <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToCategoryTwo"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + + <actionGroup ref="AdminAssertProductInfoOnEditPageActionGroup" stepKey="assertProductInfo"> + <argument name="product" value="simpleProductEnabledFlat"/> + </actionGroup> + + <actionGroup ref="StorefrontNavigateCategoryPageActionGroup" stepKey="openCategoryPage"> + <argument name="category" value="$categoryEntity$"/> + </actionGroup> + + <actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="seeSimpleProductNameOnCategoryPage"> + <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> + </actionGroup> + + <actionGroup ref="OpenStoreFrontProductPageActionGroup" stepKey="goToProductPage"> + <argument name="productUrlKey" value="{{simpleProductEnabledFlat.urlKey}}"/> + </actionGroup> + + <actionGroup ref="StorefrontAssertProductNameOnProductPageActionGroup" stepKey="seeSimpleProductNameOnStoreFrontPage"> + <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeSimpleProductPriceOnStoreFrontPage"> + <argument name="productPrice" value="{{simpleProductEnabledFlat.price}}"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeSimpleProductSKUOnStoreFrontPage"> <argument name="productSku" value="{{simpleProductEnabledFlat.sku}}"/> </actionGroup> - <grabTextFrom selector="{{StorefrontProductInfoMainSection.productStockStatus}}" stepKey="productStockAvailableStatus"/> - <assertEquals stepKey="assertStockAvailableOnProductPage"> - <expectedResult type="string">{{simpleProductEnabledFlat.storefrontStatus}}</expectedResult> - <actualResult type="variable">productStockAvailableStatus</actualResult> - </assertEquals> - <grabTextFrom selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="productPriceAmount"/> - <assertEquals stepKey="assertOldPriceTextOnProductPage"> - <expectedResult type="string">${{simpleProductEnabledFlat.price}}</expectedResult> - <actualResult type="variable">productPriceAmount</actualResult> - </assertEquals> - - <!--Verify customer see updated simple product link on magento storefront page and is searchable by sku --> - <amOnPage url="{{StorefrontProductPage.url(simpleProductEnabledFlat.urlKey)}}" stepKey="goToMagentoStorefrontPage"/> - <waitForPageLoad stepKey="waitForStoreFrontProductPageLoad"/> - <fillField selector="{{StorefrontQuickSearchResultsSection.searchTextBox}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="fillSimpleProductSkuInSearchTextBox"/> - <waitForPageLoad stepKey="waitForSearchTextBox"/> - <click selector="{{StorefrontQuickSearchResultsSection.searchTextBoxButton}}" stepKey="clickSearchTextBoxButton"/> - <waitForPageLoad stepKey="waitForSearch"/> - <see selector="{{StorefrontQuickSearchResultsSection.productLink}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductNameOnMagentoStorefrontPage"/> + <actionGroup ref="StorefrontAssertProductStockStatusOnProductPageActionGroup" stepKey="seeSimpleProductStockStatusOnStoreFrontPage"> + <argument name="productStockStatus" value="{{simpleProductEnabledFlat.storefrontStatus}}"/> + </actionGroup> + + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToHomepage"/> + <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="searchForSku"> + <argument name="phrase" value="{{simpleProductEnabledFlat.sku}}"/> + </actionGroup> + <actionGroup ref="StorefrontOpenProductFromQuickSearchActionGroup" stepKey="openAndCheckProduct"> + <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> + <argument name="productUrlKey" value="{{simpleProductEnabledFlat.urlKey}}"/> + </actionGroup> + </test> </tests> From e4fde6b8c5005c984c7f8dab1c6106c7f5649be5 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 9 Dec 2020 12:47:29 +0200 Subject: [PATCH 220/346] added deprecation, refactored --- ...AssertManageStockOnEditPageActionGroup.xml | 3 +- ...AssertProductInfoOnEditPageActionGroup.xml | 2 +- ...uctStockStatusOnProductPageActionGroup.xml | 3 +- ...ularPriceInStockEnabledFlatCatalogTest.xml | 122 ++++++++++++ ...WithRegularPriceInStockEnabledFlatTest.xml | 173 ++++++++++-------- 5 files changed, 224 insertions(+), 79 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml index f9c9098732476..67df650a24228 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml @@ -10,7 +10,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminAssertManageStockOnEditPageActionGroup"> <annotations> - <description>Check if manageStock value is correct (the Product Edit page should be opened in Admin prior this check).</description> + <description>Check if manageStock value is correct + (the Product Edit page->Advanced Inventory section should be opened in Admin prior this check).</description> </annotations> <arguments> <argument name="manageStock" type="string"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml index b70c7a4d62dcf..bbfbcf584fa0a 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml @@ -10,7 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminAssertProductInfoOnEditPageActionGroup"> <annotations> - <description>Validates next fields on the Edit Product Page: name, sku, price, quantity, stock status, tax class, weight, weigh select, visibility, url key</description> + <description>Validates next fields on the Product Edit Page: name, sku, price, quantity, stock status, tax class, weight, weigh select, visibility, url key</description> </annotations> <arguments> <argument name="product" type="entity"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml index 356302ef26b9c..5af46bcd734d1 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml @@ -9,7 +9,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="StorefrontAssertProductStockStatusOnProductPageActionGroup"> <annotations> - <description>Validate that the provided Product Stock Status is present and correct (the Product Detail page should be opened on Storefront prior this check)</description> + <description>Validates that the provided Product Stock Status is present and correct + (the Product Detail page should be opened on Storefront prior this check)</description> </annotations> <arguments> <argument name="productStockStatus" type="string"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml new file mode 100644 index 0000000000000..c083f827e8930 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml @@ -0,0 +1,122 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest"> + <annotations> + <stories value="Update Simple Product"/> + <title value="Update Simple Product with Regular Price (In Stock) Enabled Flat"/> + <description value="Test log in to Update Simple Product and Update Simple Product with Regular Price (In Stock) Enabled Flat"/> + <testCaseId value="MC-10818"/> + <severity value="CRITICAL"/> + <group value="catalog"/> + <group value="mtf_migrated"/> + </annotations> + <before> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <magentoCLI stepKey="setFlatCatalogProduct" command="config:set catalog/frontend/flat_catalog_product 1"/> + <createData entity="SimpleSubCategory" stepKey="initialCategoryEntity"/> + <createData entity="defaultSimpleProduct" stepKey="initialSimpleProduct"> + <requiredEntity createDataKey="initialCategoryEntity"/> + </createData> + <createData entity="SimpleSubCategory" stepKey="categoryEntity"/> + </before> + <after> + <deleteData stepKey="deleteSimpleSubCategory" createDataKey="initialCategoryEntity"/> + <deleteData stepKey="deleteSimpleSubCategory2" createDataKey="categoryEntity"/> + <actionGroup ref="DeleteProductBySkuActionGroup" stepKey="deleteCreatedProduct"> + <argument name="sku" value="{{simpleProductEnabledFlat.sku}}"/> + </actionGroup> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + <magentoCLI stepKey="unsetFlatCatalogProduct" command="config:set catalog/frontend/flat_catalog_product 0"/> + </after> + + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openProductPage"> + <argument name="product" value="$$initialSimpleProduct$$"/> + </actionGroup> + + <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickAdvancedInventoryLink"/> + <actionGroup ref="AdminSetManageStockConfigActionGroup" stepKey="setManageStockConfig"> + <argument name="value" value="No"/> + </actionGroup> + <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButtonOnAdvancedInventorySection"/> + + <actionGroup ref="AdminAssignTwoCategoriesToProductActionGroup" stepKey="assignCategories"> + <argument name="categoryName" value="$$initialCategoryEntity.name$$"/> + <argument name="categoryTwoName" value="$$categoryEntity.name$$"/> + </actionGroup> + + <actionGroup ref="AdminFillMainProductFormActionGroup" stepKey="fillSimpleProductInfo"> + <argument name="product" value="simpleProductEnabledFlat"/> + </actionGroup> + + <actionGroup ref="AdminProductFormSaveButtonClickActionGroup" stepKey="clickSaveButton"/> + + <see selector="{{AdminProductFormSection.successMessage}}" userInput="You saved the product." stepKey="seeSimpleProductSavedSuccessMessage"/> + + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage1"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openProductPage1"> + <argument name="product" value="simpleProductEnabledFlat"/> + </actionGroup> + + <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickTheAdvancedInventoryLink1"/> + <actionGroup ref="AdminAssertManageStockOnEditPageActionGroup" stepKey="assertManageStock1"> + <argument name="manageStock" value="No"/> + </actionGroup> + <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButtonOnAdvancedInventorySection1"/> + + <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToInitialCategory"> + <argument name="categoryName" value="$$initialCategoryEntity.name$$"/> + </actionGroup> + + <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToCategoryTwo"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + + <actionGroup ref="AdminAssertProductInfoOnEditPageActionGroup" stepKey="assertProductInfo"> + <argument name="product" value="simpleProductEnabledFlat"/> + </actionGroup> + + <actionGroup ref="StorefrontNavigateCategoryPageActionGroup" stepKey="openCategoryPage"> + <argument name="category" value="$categoryEntity$"/> + </actionGroup> + + <actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="seeSimpleProductNameOnCategoryPage"> + <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> + </actionGroup> + + <actionGroup ref="OpenStoreFrontProductPageActionGroup" stepKey="goToProductPage"> + <argument name="productUrlKey" value="{{simpleProductEnabledFlat.urlKey}}"/> + </actionGroup> + + <actionGroup ref="StorefrontAssertProductNameOnProductPageActionGroup" stepKey="seeSimpleProductNameOnStoreFrontPage"> + <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeSimpleProductPriceOnStoreFrontPage"> + <argument name="productPrice" value="{{simpleProductEnabledFlat.price}}"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeSimpleProductSKUOnStoreFrontPage"> + <argument name="productSku" value="{{simpleProductEnabledFlat.sku}}"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductStockStatusOnProductPageActionGroup" stepKey="seeSimpleProductStockStatusOnStoreFrontPage"> + <argument name="productStockStatus" value="{{simpleProductEnabledFlat.storefrontStatus}}"/> + </actionGroup> + + <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToHomepage"/> + <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="searchForSku"> + <argument name="phrase" value="{{simpleProductEnabledFlat.sku}}"/> + </actionGroup> + <actionGroup ref="StorefrontOpenProductFromQuickSearchActionGroup" stepKey="openAndCheckProduct"> + <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> + <argument name="productUrlKey" value="{{simpleProductEnabledFlat.urlKey}}"/> + </actionGroup> + + </test> +</tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml index 4bf15199f0db5..fd8be7be2ea5b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml @@ -6,17 +6,20 @@ */ --> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest"> + <test name="AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest" deprecated="Use AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest instead"> <annotations> <stories value="Update Simple Product"/> - <title value="Update Simple Product with Regular Price (In Stock) Enabled Flat"/> + <title value="DEPREACTED. Update Simple Product with Regular Price (In Stock) Enabled Flat"/> <description value="Test log in to Update Simple Product and Update Simple Product with Regular Price (In Stock) Enabled Flat"/> <testCaseId value="MC-10818"/> <severity value="CRITICAL"/> <group value="catalog"/> <group value="mtf_migrated"/> + <skip> + <issueId value="DEPRECATED">Use AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest instead</issueId> + </skip> </annotations> <before> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> @@ -37,86 +40,104 @@ <magentoCLI stepKey="unsetFlatCatalogProduct" command="config:set catalog/frontend/flat_catalog_product 0"/> </after> - <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openProductPage"> - <argument name="product" value="$$initialSimpleProduct$$"/> + <!-- Search default simple product in the grid page --> + <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> + <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> + <argument name="sku" value="$$initialSimpleProduct.sku$$"/> </actionGroup> + <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> + <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <!-- Update simple product with regular price --> + <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="fillSimpleProductName"/> + <fillField selector="{{AdminProductFormSection.productSku}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="fillSimpleProductSku"/> + <fillField selector="{{AdminProductFormSection.productPrice}}" userInput="{{simpleProductEnabledFlat.price}}" stepKey="fillSimpleProductPrice"/> + <selectOption selector="{{AdminProductFormSection.productTaxClass}}" userInput="{{simpleProductEnabledFlat.productTaxClass}}" stepKey="selectProductTaxClass"/> + <fillField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductEnabledFlat.quantity}}" stepKey="fillSimpleProductQuantity"/> <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickAdvancedInventoryLink"/> - <actionGroup ref="AdminSetManageStockConfigActionGroup" stepKey="setManageStockConfig"> - <argument name="value" value="No"/> - </actionGroup> + <conditionalClick selector="{{AdminProductFormAdvancedInventorySection.useConfigSettings}}" dependentSelector="{{AdminProductFormAdvancedInventorySection.useConfigSettings}}" visible="true" stepKey="checkUseConfigSettingsCheckBox"/> + <selectOption selector="{{AdminProductFormAdvancedInventorySection.manageStock}}" userInput="No" stepKey="selectManageStock"/> <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButtonOnAdvancedInventorySection"/> - - <actionGroup ref="AdminAssignTwoCategoriesToProductActionGroup" stepKey="assignCategories"> - <argument name="categoryName" value="$$initialCategoryEntity.name$$"/> - <argument name="categoryTwoName" value="$$categoryEntity.name$$"/> - </actionGroup> - - <actionGroup ref="AdminFillMainProductFormActionGroup" stepKey="fillSimpleProductInfo"> - <argument name="product" value="simpleProductEnabledFlat"/> - </actionGroup> - + <selectOption selector="{{AdminProductFormSection.stockStatus}}" userInput="{{simpleProductEnabledFlat.status}}" stepKey="selectStockStatusInStock"/> + <fillField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductEnabledFlat.weight}}" stepKey="fillSimpleProductWeight"/> + <selectOption selector="{{AdminProductFormSection.productWeightSelect}}" userInput="{{simpleProductEnabledFlat.weightSelect}}" stepKey="selectProductWeight"/> + <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDown"/> + <fillField selector="{{AdminProductFormSection.searchCategory}}" userInput="$$initialCategoryEntity.name$$" stepKey="fillSearchForInitialCategory" /> + <waitForPageLoad stepKey="waitForCategory1"/> + <click selector="{{AdminProductFormSection.selectCategory($$initialCategoryEntity.name$$)}}" stepKey="unselectInitialCategory"/> + <fillField selector="{{AdminProductFormSection.searchCategory}}" userInput="$$categoryEntity.name$$" stepKey="fillSearchCategory" /> + <waitForPageLoad stepKey="waitForCategory2"/> + <click selector="{{AdminProductFormSection.selectCategory($$categoryEntity.name$$)}}" stepKey="clickOnCategory"/> + <actionGroup ref="AdminSubmitCategoriesPopupActionGroup" stepKey="clickOnDoneAdvancedCategorySelect"/> + <selectOption selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductEnabledFlat.visibility}}" stepKey="selectVisibility"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection"/> + <fillField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{simpleProductEnabledFlat.urlKey}}" stepKey="fillUrlKey"/> + <scrollToTopOfPage stepKey="scrollToTopOfAdminProductFormSection"/> <actionGroup ref="AdminProductFormSaveButtonClickActionGroup" stepKey="clickSaveButton"/> - <see selector="{{AdminProductFormSection.successMessage}}" userInput="You saved the product." stepKey="seeSimpleProductSavedSuccessMessage"/> - - <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage1"/> - <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openProductPage1"> - <argument name="product" value="simpleProductEnabledFlat"/> - </actionGroup> - - <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickTheAdvancedInventoryLink1"/> - <actionGroup ref="AdminAssertManageStockOnEditPageActionGroup" stepKey="assertManageStock1"> - <argument name="manageStock" value="No"/> - </actionGroup> - <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButtonOnAdvancedInventorySection1"/> - - <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToInitialCategory"> - <argument name="categoryName" value="$$initialCategoryEntity.name$$"/> - </actionGroup> - - <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToCategoryTwo"> - <argument name="categoryName" value="$$categoryEntity.name$$"/> - </actionGroup> - - <actionGroup ref="AdminAssertProductInfoOnEditPageActionGroup" stepKey="assertProductInfo"> - <argument name="product" value="simpleProductEnabledFlat"/> - </actionGroup> - - <actionGroup ref="StorefrontNavigateCategoryPageActionGroup" stepKey="openCategoryPage"> - <argument name="category" value="$categoryEntity$"/> - </actionGroup> - - <actionGroup ref="AssertStorefrontProductIsPresentOnCategoryPageActionGroup" stepKey="seeSimpleProductNameOnCategoryPage"> - <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> - </actionGroup> - - <actionGroup ref="OpenStoreFrontProductPageActionGroup" stepKey="goToProductPage"> - <argument name="productUrlKey" value="{{simpleProductEnabledFlat.urlKey}}"/> - </actionGroup> - - <actionGroup ref="StorefrontAssertProductNameOnProductPageActionGroup" stepKey="seeSimpleProductNameOnStoreFrontPage"> - <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> - </actionGroup> - <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeSimpleProductPriceOnStoreFrontPage"> - <argument name="productPrice" value="{{simpleProductEnabledFlat.price}}"/> - </actionGroup> - <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeSimpleProductSKUOnStoreFrontPage"> + <!-- Verify customer see success message --> + <see selector="{{AdminProductFormSection.successMessage}}" userInput="You saved the product." stepKey="seeAssertSimpleProductSaveSuccessMessage"/> + + <!-- Search updated simple product(from above step) in the grid page --> + <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPageToSearchUpdatedSimpleProduct"/> + <conditionalClick selector="{{AdminProductGridFilterSection.clearAll}}" dependentSelector="{{AdminProductGridFilterSection.clearAll}}" visible="true" stepKey="clickClearAll"/> + <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="clickFiltersButton"/> + <fillField selector="{{AdminProductGridFilterSection.nameFilter}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="fillSimpleProductNameInNameFilter"/> + <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="fillProductSku"/> + <click selector="{{AdminProductGridFilterSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> + <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToVerifyUpdatedSimpleProductVisibleInGrid"/> + <waitForPageLoad stepKey="waitUntilSimpleProductPageIsOpened"/> + + <!-- Verify customer see updated simple product in the product form page --> + <seeInField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductName"/> + <seeInField selector="{{AdminProductFormSection.productSku}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="seeSimpleProductSku"/> + <seeInField selector="{{AdminProductFormSection.productPrice}}" userInput="{{simpleProductEnabledFlat.price}}" stepKey="seeSimpleProductPrice"/> + <seeInField selector="{{AdminProductFormSection.productTaxClass}}" userInput="{{simpleProductEnabledFlat.productTaxClass}}" stepKey="seeProductTaxClass"/> + <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductEnabledFlat.quantity}}" stepKey="seeSimpleProductQuantity"/> + <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickTheAdvancedInventoryLink"/> + <see selector="{{AdminProductFormAdvancedInventorySection.manageStock}}" userInput="No" stepKey="seeManageStock"/> + <click selector="{{AdminProductFormAdvancedInventorySection.advancedInventoryCloseButton}}" stepKey="clickDoneButtonOnAdvancedInventory"/> + <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductEnabledFlat.status}}" stepKey="seeSimpleProductStockStatus"/> + <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductEnabledFlat.weight}}" stepKey="seeSimpleProductWeight"/> + <seeInField selector="{{AdminProductFormSection.productWeightSelect}}" userInput="{{simpleProductEnabledFlat.weightSelect}}" stepKey="seeSimpleProductWeightSelect"/> + <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> + <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="seeSelectedCategories" /> + <seeInField selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductEnabledFlat.visibility}}" stepKey="seeVisibility"/> + <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> + <seeInField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{simpleProductEnabledFlat.urlKey}}" stepKey="seeUrlKey"/> + + <!--Verify customer see updated simple product link on category page --> + <amOnPage url="{{StorefrontCategoryPage.url($$categoryEntity.name$$)}}" stepKey="openCategoryPage"/> + <waitForPageLoad stepKey="waitForCategoryPageLoad"/> + <see selector="{{StorefrontCategoryMainSection.productLink}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductNameOnCategoryPage"/> + + <!-- Verify customer see updated simple product (from the above step) on the storefront page --> + <amOnPage url="{{StorefrontProductPage.url(simpleProductEnabledFlat.urlKey)}}" stepKey="goToProductPage"/> + <waitForPageLoad stepKey="waitForStorefrontProductPageLoad"/> + <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductNameOnStoreFrontPage"/> + <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="{{simpleProductEnabledFlat.price}}" stepKey="seeSimpleProductPriceOnStoreFrontPage"/> + <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeSimpleProductSkuOnStoreFrontPage"> <argument name="productSku" value="{{simpleProductEnabledFlat.sku}}"/> </actionGroup> - <actionGroup ref="StorefrontAssertProductStockStatusOnProductPageActionGroup" stepKey="seeSimpleProductStockStatusOnStoreFrontPage"> - <argument name="productStockStatus" value="{{simpleProductEnabledFlat.storefrontStatus}}"/> - </actionGroup> - - <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToHomepage"/> - <actionGroup ref="StorefrontCheckQuickSearchStringActionGroup" stepKey="searchForSku"> - <argument name="phrase" value="{{simpleProductEnabledFlat.sku}}"/> - </actionGroup> - <actionGroup ref="StorefrontOpenProductFromQuickSearchActionGroup" stepKey="openAndCheckProduct"> - <argument name="productName" value="{{simpleProductEnabledFlat.name}}"/> - <argument name="productUrlKey" value="{{simpleProductEnabledFlat.urlKey}}"/> - </actionGroup> - + <grabTextFrom selector="{{StorefrontProductInfoMainSection.productStockStatus}}" stepKey="productStockAvailableStatus"/> + <assertEquals stepKey="assertStockAvailableOnProductPage"> + <expectedResult type="string">{{simpleProductEnabledFlat.storefrontStatus}}</expectedResult> + <actualResult type="variable">productStockAvailableStatus</actualResult> + </assertEquals> + <grabTextFrom selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="productPriceAmount"/> + <assertEquals stepKey="assertOldPriceTextOnProductPage"> + <expectedResult type="string">${{simpleProductEnabledFlat.price}}</expectedResult> + <actualResult type="variable">productPriceAmount</actualResult> + </assertEquals> + + <!--Verify customer see updated simple product link on magento storefront page and is searchable by sku --> + <amOnPage url="{{StorefrontProductPage.url(simpleProductEnabledFlat.urlKey)}}" stepKey="goToMagentoStorefrontPage"/> + <waitForPageLoad stepKey="waitForStoreFrontProductPageLoad"/> + <fillField selector="{{StorefrontQuickSearchResultsSection.searchTextBox}}" userInput="{{simpleProductEnabledFlat.sku}}" stepKey="fillSimpleProductSkuInSearchTextBox"/> + <waitForPageLoad stepKey="waitForSearchTextBox"/> + <click selector="{{StorefrontQuickSearchResultsSection.searchTextBoxButton}}" stepKey="clickSearchTextBoxButton"/> + <waitForPageLoad stepKey="waitForSearch"/> + <see selector="{{StorefrontQuickSearchResultsSection.productLink}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="seeSimpleProductNameOnMagentoStorefrontPage"/> </test> </tests> From 1dd1046fba15c8b72e50cd2114a554fd65b06eea Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 9 Dec 2020 12:55:09 +0200 Subject: [PATCH 221/346] fixed a typo --- .../AdminAssertProductInfoOnEditPageActionGroup.xml | 3 ++- ...dateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml index bbfbcf584fa0a..ba67168958fca 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml @@ -10,7 +10,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminAssertProductInfoOnEditPageActionGroup"> <annotations> - <description>Validates next fields on the Product Edit Page: name, sku, price, quantity, stock status, tax class, weight, weigh select, visibility, url key</description> + <description>Validates next fields on the Product Edit Page: + name, sku, price, quantity, stock status, tax class, weight, weigh select, visibility, url key</description> </annotations> <arguments> <argument name="product" type="entity"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml index fd8be7be2ea5b..c1b80b94179fa 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml @@ -11,7 +11,7 @@ <test name="AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest" deprecated="Use AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest instead"> <annotations> <stories value="Update Simple Product"/> - <title value="DEPREACTED. Update Simple Product with Regular Price (In Stock) Enabled Flat"/> + <title value="DEPRECACTED. Update Simple Product with Regular Price (In Stock) Enabled Flat"/> <description value="Test log in to Update Simple Product and Update Simple Product with Regular Price (In Stock) Enabled Flat"/> <testCaseId value="MC-10818"/> <severity value="CRITICAL"/> From ff979509acc574f3f95a3cdd19c685eba7645a49 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Wed, 9 Dec 2020 13:27:07 +0200 Subject: [PATCH 222/346] fix for document type --- app/code/Magento/Dhl/Model/Carrier.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Dhl/Model/Carrier.php b/app/code/Magento/Dhl/Model/Carrier.php index 0f853561571af..513e15c2a4dc4 100644 --- a/app/code/Magento/Dhl/Model/Carrier.php +++ b/app/code/Magento/Dhl/Model/Carrier.php @@ -1776,7 +1776,7 @@ protected function _shipmentDetails($xml, $rawRequest, $originRegion = '') $nodeShipmentDetails->addChild('DoorTo', 'DD'); $nodeShipmentDetails->addChild('DimensionUnit', substr($this->_getDimensionUnit(), 0, 1)); $contentType = isset($package['params']['container']) ? $package['params']['container'] : ''; - $packageType = $contentType === self::DHL_CONTENT_TYPE_NON_DOC ? 'CP' : ''; + $packageType = $contentType === self::DHL_CONTENT_TYPE_NON_DOC ? 'CP' : 'EE'; $nodeShipmentDetails->addChild('PackageType', $packageType); if ($this->isDutiable($rawRequest->getOrigCountryId(), $rawRequest->getDestCountryId())) { $nodeShipmentDetails->addChild('IsDutiable', 'Y'); From c5d2d01e33958ac4d1fdffa5dd0c95aac3c474cc Mon Sep 17 00:00:00 2001 From: Sergiy Vasiutynskyi <s.vasiutynskyi@atwix.com> Date: Wed, 9 Dec 2020 16:16:25 +0200 Subject: [PATCH 223/346] Removed usage or changed value of CliIndexerReindexActionGroup action group for Catalog module --- ...utOfStockProductIsVisibleInCategoryTest.xml | 5 +---- .../AdminCreateCategoryWithAnchorFieldTest.xml | 5 +---- ...tiveFlatCategoryAndUpdateAsInactiveTest.xml | 14 +++----------- .../AdminCreateInactiveFlatCategoryTest.xml | 12 +++--------- ...minCreateInactiveInMenuFlatCategoryTest.xml | 12 +++--------- ...eateProductAttributeFromProductPageTest.xml | 5 +---- ...AdminCreateSimpleProductWithUnicodeTest.xml | 4 +--- ...hCustomOptionsSuiteAndImportOptionsTest.xml | 4 +--- ...inCreateVirtualProductWithTierPriceTest.xml | 5 +---- ...ProductsImageInCaseOfMultipleStoresTest.xml | 9 ++------- ...tCustomizableOptionToProductWithSKUTest.xml | 5 +---- ...veAnchoredCategoryToDefaultCategoryTest.xml | 5 +---- ...dminMoveCategoryAndCheckUrlRewritesTest.xml | 5 +---- ...eCategoryFromParentAnchoredCategoryTest.xml | 5 +---- ...signedToCategoryWithoutCustomURLKeyTest.xml | 5 +---- .../AdminRemoveImageAffectsAllScopesTest.xml | 4 +--- .../Mftf/Test/AdminSortingByWebsitesTest.xml | 4 +--- ...minUpdateFlatCategoryAndAddProductsTest.xml | 18 ++++-------------- ...dateFlatCategoryIncludeInNavigationTest.xml | 3 +-- ...torefrontProductNameWithDoubleQuoteTest.xml | 5 +---- 20 files changed, 30 insertions(+), 104 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckOutOfStockProductIsVisibleInCategoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckOutOfStockProductIsVisibleInCategoryTest.xml index 9c1ff43587a27..db789d3512acf 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckOutOfStockProductIsVisibleInCategoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckOutOfStockProductIsVisibleInCategoryTest.xml @@ -69,10 +69,7 @@ </actionGroup> <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButton"/> <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct"/> - <!--Run re-index task --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!--Verify product is visible in category front page --> <actionGroup ref="StorefrontOpenHomePageActionGroup" stepKey="goToHomepage"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateCategoryWithAnchorFieldTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateCategoryWithAnchorFieldTest.xml index 3332bc66653e5..8d0534891a29b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateCategoryWithAnchorFieldTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateCategoryWithAnchorFieldTest.xml @@ -70,10 +70,7 @@ <argument name="targetPath" value="catalog/category/view/id/{$categoryId}"/> </actionGroup> - <!--Clear cache and reindex--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryAndUpdateAsInactiveTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryAndUpdateAsInactiveTest.xml index 500c95d1120f3..7447c75a778af 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryAndUpdateAsInactiveTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryAndUpdateAsInactiveTest.xml @@ -30,10 +30,7 @@ <actionGroup ref="CreateStoreViewActionGroup" stepKey="createCustomStoreViewFr"> <argument name="storeView" value="customStoreFR"/> </actionGroup> - <!--Run full reindex and clear caches --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> @@ -47,9 +44,7 @@ <after> <magentoCLI stepKey="setFlatCatalogCategory" command="config:set catalog/frontend/flat_catalog_category 0 "/> <magentoCLI stepKey="setIndexerMode" command="indexer:set-mode" arguments="realtime" /> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="indexerReindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="indexerReindex"/> <deleteData stepKey="deleteCategory" createDataKey="createCategory"/> <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreViewEn"> <argument name="customStore" value="customStoreEN"/> @@ -68,10 +63,7 @@ <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccessMessage"/> <see selector="{{AdminCategoryContentSection.categoryPageTitle}}" userInput="{{CatNotActive.name}}" stepKey="seeUpdatedCategoryTitle"/> <dontSeeCheckboxIsChecked selector="{{AdminCategoryBasicFieldSection.enableCategoryLabel}}" stepKey="verifyInactiveCategory"/> - <!--Run full reindex and clear caches --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryTest.xml index 2394b41502f84..df2124759686d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveFlatCategoryTest.xml @@ -30,10 +30,7 @@ <actionGroup ref="CreateStoreViewActionGroup" stepKey="createCustomStoreViewFr"> <argument name="storeView" value="customStoreFR"/> </actionGroup> - <!--Run full reindex and clear caches --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> @@ -47,9 +44,7 @@ <after> <magentoCLI stepKey="setFlatCatalogCategory" command="config:set catalog/frontend/flat_catalog_category 0 "/> <magentoCLI stepKey="setIndexerMode" command="indexer:set-mode" arguments="realtime" /> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="indexerReindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="indexerReindex"/> <deleteData stepKey="deleteCategory" createDataKey="createCategory"/> <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreViewEn"> <argument name="customStore" value="customStoreEN"/> @@ -69,9 +64,8 @@ <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccessMessage"/> <see selector="{{AdminCategoryContentSection.categoryPageTitle}}" userInput="{{SimpleSubCategory.name}}" stepKey="seeUpdatedCategoryTitle"/> <dontSeeCheckboxIsChecked selector="{{AdminCategoryBasicFieldSection.enableCategoryLabel}}" stepKey="verifyInactiveIncludeInMenu"/> - <!--Run full reindex and clear caches --> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> + <argument name="indices" value="catalog_category_flat"/> </actionGroup> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveInMenuFlatCategoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveInMenuFlatCategoryTest.xml index 35e53273aebf2..2f86209da1eba 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveInMenuFlatCategoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateInactiveInMenuFlatCategoryTest.xml @@ -30,10 +30,7 @@ <actionGroup ref="CreateStoreViewActionGroup" stepKey="createCustomStoreViewFr"> <argument name="storeView" value="customStoreFR"/> </actionGroup> - <!--Run full reindex and clear caches --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> @@ -47,9 +44,7 @@ <after> <magentoCLI stepKey="setFlatCatalogCategory" command="config:set catalog/frontend/flat_catalog_category 0 "/> <magentoCLI stepKey="setIndexerMode" command="indexer:set-mode" arguments="realtime" /> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="indexerReindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="indexerReindex"/> <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreViewEn"> <argument name="customStore" value="customStoreEN"/> </actionGroup> @@ -70,9 +65,8 @@ <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccessMessage"/> <see selector="{{AdminCategoryContentSection.categoryPageTitle}}" userInput="{{SimpleSubCategory.name}}" stepKey="seeUpdatedCategoryTitle"/> <dontSeeCheckboxIsChecked selector="{{AdminCategoryBasicFieldSection.includeInMenuLabel}}" stepKey="verifyInactiveIncludeInMenu"/> - <!--Run full reindex and clear caches --> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> + <argument name="indices" value="catalog_category_flat"/> </actionGroup> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductAttributeFromProductPageTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductAttributeFromProductPageTest.xml index 61ef389c7909e..2619e5e415686 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductAttributeFromProductPageTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductAttributeFromProductPageTest.xml @@ -88,10 +88,7 @@ <actionGroup ref="AdminProductFormSaveButtonClickActionGroup" stepKey="saveTheProduct"/> <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the product." stepKey="messageYouSavedTheProductIsShown"/> - <!--Run Re-Index task --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!--Verify product attribute added in product form --> <scrollTo selector="{{AdminProductFormSection.contentTab}}" stepKey="scrollToContentTab"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateSimpleProductWithUnicodeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateSimpleProductWithUnicodeTest.xml index 54c3a05651c44..a00714e412b0a 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateSimpleProductWithUnicodeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateSimpleProductWithUnicodeTest.xml @@ -31,9 +31,7 @@ <argument name="category" value="$$createPreReqCategory$$"/> <argument name="simpleProduct" value="ProductWithUnicode"/> </actionGroup> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithCustomOptionsSuiteAndImportOptionsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithCustomOptionsSuiteAndImportOptionsTest.xml index 7871f4305575a..3141db87f6976 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithCustomOptionsSuiteAndImportOptionsTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithCustomOptionsSuiteAndImportOptionsTest.xml @@ -117,9 +117,7 @@ <!-- Verify we see success message --> <see selector="{{AdminProductFormSection.successMessage}}" userInput="You saved the product." stepKey="seeAssertVirtualProductSuccessMessage"/> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithTierPriceTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithTierPriceTest.xml index 994ea76ca33df..f2840758d59a6 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithTierPriceTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateVirtualProductWithTierPriceTest.xml @@ -95,10 +95,7 @@ <waitForPageLoad stepKey="waitForCategoryPageToLoad"/> <see selector="{{StorefrontCategoryMainSection.productLink}}" userInput="{{virtualProductBigQty.name}}" stepKey="seeVirtualProductNameOnCategoryPage"/> - <!--Run full reindex and clear caches --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminDeleteProductsImageInCaseOfMultipleStoresTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminDeleteProductsImageInCaseOfMultipleStoresTest.xml index 7e5ee977d679b..3514f53e8b937 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminDeleteProductsImageInCaseOfMultipleStoresTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminDeleteProductsImageInCaseOfMultipleStoresTest.xml @@ -65,9 +65,7 @@ <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteWebsite"> <argument name="websiteName" value="{{NewWebSiteData.name}}"/> </actionGroup> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> @@ -96,10 +94,7 @@ <argument name="website" value="{{NewWebSiteData.name}}"/> </actionGroup> <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct2"/> - <!--Reindex and flush cache--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminImportCustomizableOptionToProductWithSKUTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminImportCustomizableOptionToProductWithSKUTest.xml index af31b7c1d5c07..4dd76e55f9330 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminImportCustomizableOptionToProductWithSKUTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminImportCustomizableOptionToProductWithSKUTest.xml @@ -31,10 +31,7 @@ <requiredEntity createDataKey="createCategory"/> </createData> - <!-- TODO: REMOVE AFTER FIX MC-21717 --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveAnchoredCategoryToDefaultCategoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveAnchoredCategoryToDefaultCategoryTest.xml index 809a015369ea9..3da19eb598012 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveAnchoredCategoryToDefaultCategoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveAnchoredCategoryToDefaultCategoryTest.xml @@ -65,10 +65,7 @@ <actionGroup ref="AdminSaveCategoryActionGroup" stepKey="saveSubCategory2"/> <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccessMessage2"/> - <!-- TODO: REMOVE AFTER FIX MC-21717 --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryAndCheckUrlRewritesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryAndCheckUrlRewritesTest.xml index 9100e6027a52f..1c55b09151cf3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryAndCheckUrlRewritesTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryAndCheckUrlRewritesTest.xml @@ -22,10 +22,7 @@ <createData entity="FirstLevelSubCat" stepKey="createDefaultCategory"> <field key="is_active">true</field> </createData> - <!-- Perform reindex and flush cache --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryFromParentAnchoredCategoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryFromParentAnchoredCategoryTest.xml index 0e056e4bb7078..fe3ffbb4fc1d7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryFromParentAnchoredCategoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMoveCategoryFromParentAnchoredCategoryTest.xml @@ -56,10 +56,7 @@ <actionGroup ref="AdminSaveCategoryActionGroup" stepKey="saveSubCategory1"/> <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccessMessage"/> - <!--Run re-index task --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!--Verify category displayed in store front page--> <amOnPage url="/$$createDefaultCategory.name$$/{{SimpleSubCategory.name}}.html" stepKey="seeTheCategoryInStoreFrontPage"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCustomURLKeyPreservedWhenAssignedToCategoryWithoutCustomURLKeyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCustomURLKeyPreservedWhenAssignedToCategoryWithoutCustomURLKeyTest.xml index 8e728fc6e1f27..e06a7f3c5679c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCustomURLKeyPreservedWhenAssignedToCategoryWithoutCustomURLKeyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminProductCustomURLKeyPreservedWhenAssignedToCategoryWithoutCustomURLKeyTest.xml @@ -34,10 +34,7 @@ <argument name="customStore" value="storeViewData"/> </actionGroup> - <!--Run full reindex and clear caches --> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value="full_page"/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml index 1707fda9e3edb..e989aa3758cf3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml @@ -65,9 +65,7 @@ </actionGroup> <deleteData createDataKey="category" stepKey="deletePreReqCategory"/> <deleteData createDataKey="product" stepKey="deleteFirstProduct"/> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminSortingByWebsitesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSortingByWebsitesTest.xml index 73aeed3af4fb0..f5046faf82b6f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminSortingByWebsitesTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminSortingByWebsitesTest.xml @@ -45,9 +45,7 @@ <actionGroup ref="AdminOpenCatalogProductPageActionGroup" stepKey="goToProductCatalogPage"/> <actionGroup ref="ResetProductGridToDefaultViewActionGroup" stepKey="resetProductGridColumnsInitial"/> <actionGroup ref="ResetWebUrlOptionsActionGroup" stepKey="resetUrlOption"/> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryAndAddProductsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryAndAddProductsTest.xml index 208b588493112..f7f87da77b401 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryAndAddProductsTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryAndAddProductsTest.xml @@ -35,9 +35,7 @@ <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!--Enable Flat Catalog Category --> <magentoCLI stepKey="setFlatCatalogCategory" command="config:set catalog/frontend/flat_catalog_category 1"/> <!--Open Index Management Page and Select Index mode "Update by Schedule" --> @@ -48,9 +46,7 @@ <after> <magentoCLI stepKey="setFlatCatalogCategory" command="config:set catalog/frontend/flat_catalog_category 0 "/> <magentoCLI stepKey="setIndexersMode" command="indexer:set-mode" arguments="realtime" /> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="indexerReindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="indexerReindex"/> <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreViewEn"> <argument name="customStore" value="customStoreEN"/> </actionGroup> @@ -61,10 +57,7 @@ <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> </after> - <!-- Select Created Category--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexBeforeFlow"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindexBeforeFlow"/> <actionGroup ref="AdminOpenCategoryPageActionGroup" stepKey="openAdminCategoryIndexPage"/> <actionGroup ref="AdminExpandCategoryTreeActionGroup" stepKey="clickOnExpandTree"/> <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(SimpleSubCategory.name)}}" stepKey="selectCreatedCategory"/> @@ -82,10 +75,7 @@ <click selector="{{AdminCategoryContentSection.productTableRow}}" stepKey="selectProductFromTableRow"/> <actionGroup ref="AdminSaveCategoryActionGroup" stepKey="saveSubCategory"/> <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccessMessage"/> - <!--Open Index Management Page and verify flat categoryIndex status--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryIncludeInNavigationTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryIncludeInNavigationTest.xml index a688dea47a0c4..b316e3194c986 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryIncludeInNavigationTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateFlatCategoryIncludeInNavigationTest.xml @@ -64,9 +64,8 @@ <click selector="{{AdminCategoryBasicFieldSection.includeInMenuLabel}}" stepKey="enableIncludeInMenuOption"/> <actionGroup ref="AdminSaveCategoryActionGroup" stepKey="saveSubCategory"/> <seeElement selector="{{AdminCategoryMessagesSection.SuccessMessage}}" stepKey="seeSuccessMessage"/> - <!--Run full reindex and clear caches --> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> + <argument name="indices" value="catalog_category_flat"/> </actionGroup> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuoteTest/StorefrontProductNameWithDoubleQuoteTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuoteTest/StorefrontProductNameWithDoubleQuoteTest.xml index 67ca04a0a4594..1032c322053da 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuoteTest/StorefrontProductNameWithDoubleQuoteTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductNameWithDoubleQuoteTest/StorefrontProductNameWithDoubleQuoteTest.xml @@ -39,10 +39,7 @@ </actionGroup> <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct"/> - <!--Run re-index task--> - <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> - <argument name="indices" value=""/> - </actionGroup> + <comment userInput="Adding the comment to replace CliIndexerReindexActionGroup action group ('indexer:reindex' commands) for preserving Backward Compatibility" stepKey="reindex"/> <!--Check product in category listing--> <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="goToCategoryPage"/> From 8749553fca0ce2b626bd45d4af2f72815a46c458 Mon Sep 17 00:00:00 2001 From: "vadim.malesh" <engcom-vendorworker-charlie@adobe.com> Date: Wed, 9 Dec 2020 17:51:56 +0200 Subject: [PATCH 224/346] test dhl request when product name contains special chars --- .../Magento/Dhl/Model/CarrierTest.php | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Dhl/Model/CarrierTest.php b/dev/tests/integration/testsuite/Magento/Dhl/Model/CarrierTest.php index f9a1d2923e5be..552040489e253 100644 --- a/dev/tests/integration/testsuite/Magento/Dhl/Model/CarrierTest.php +++ b/dev/tests/integration/testsuite/Magento/Dhl/Model/CarrierTest.php @@ -17,19 +17,22 @@ use Magento\Quote\Model\Quote\Address\RateRequest; use Magento\Quote\Model\Quote\Address\RateResult\Error; use Magento\Shipping\Model\Shipment\Request; +use Magento\Shipping\Model\Simplexml\Element as ShippingElement; use Magento\Shipping\Model\Tracking\Result\Status; use Magento\Store\Model\ScopeInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\HTTP\AsyncClientInterfaceMock; -use Magento\Shipping\Model\Simplexml\Element as ShippingElement; +use PHPUnit\Framework\TestCase; /** * Test for DHL integration. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class CarrierTest extends \PHPUnit\Framework\TestCase +class CarrierTest extends TestCase { + private const PRODUCT_NAME_SPECIAL_CHARS = 'Φυστίκι Ψημένο με Αλάτι Συσκευασία'; + /** * @var Carrier */ @@ -254,10 +257,16 @@ private function assertTrackingResult($expectedTrackingData, $trackingResults): * @param string $origCountryId * @param string $expectedRegionCode * @param string $destCountryId + * @param bool|null $isProductNameContainsSpecialChars + * @return void * @dataProvider requestToShipmentDataProvider */ - public function testRequestToShip(string $origCountryId, string $expectedRegionCode, string $destCountryId): void - { + public function testRequestToShip( + string $origCountryId, + string $expectedRegionCode, + string $destCountryId, + bool $isProductNameContainsSpecialChars = false + ): void { $this->config->setValue( 'shipping/origin/country_id', $origCountryId, @@ -274,6 +283,8 @@ public function testRequestToShip(string $origCountryId, string $expectedRegionC ) ] ); + $productName = $isProductNameContainsSpecialChars ? self::PRODUCT_NAME_SPECIAL_CHARS : 'item_name'; + //phpcs:enable Magento2.Functions.DiscouragedFunction $request = new Request( [ @@ -291,7 +302,7 @@ public function testRequestToShip(string $origCountryId, string $expectedRegionC ], 'items' => [ 'item1' => [ - 'name' => 'item_name', + 'name' => $productName, ], ], ], @@ -329,10 +340,15 @@ public function testRequestToShip(string $origCountryId, string $expectedRegionC $requestElement->Request->ServiceHeader->MessageReference = 'MAGE_SHIP_28TO32_Char_CHECKED'; $requestElement->Request->ServiceHeader->MessageTime = 'currentTime'; $requestElement->ShipmentDetails->Date = 'currentTime'; - $this->assertXmlStringEqualsXmlString( - $this->getExpectedLabelRequestXml($origCountryId, $destCountryId, $expectedRegionCode), - $requestElement->asXML() + + $expectedLabelRequest = $this->getExpectedLabelRequestXml( + $origCountryId, + $destCountryId, + $expectedRegionCode, + $isProductNameContainsSpecialChars ); + + $this->assertXmlStringEqualsXmlString($expectedLabelRequest, $requestElement->asXML()); } /** @@ -351,7 +367,10 @@ public function requestToShipmentDataProvider(): array ], [ 'DE', 'EU', 'DE' - ] + ], + [ + 'GB', 'EU', 'US', true + ], ]; } @@ -361,12 +380,14 @@ public function requestToShipmentDataProvider(): array * @param string $origCountryId * @param string $destCountryId * @param string $regionCode + * @param bool $isProductNameContainsSpecialChars * @return string */ private function getExpectedLabelRequestXml( string $origCountryId, string $destCountryId, - string $regionCode + string $regionCode, + bool $isProductNameContainsSpecialChars ): string { $countryNames = [ 'US' => 'United States Of America', @@ -387,6 +408,10 @@ private function getExpectedLabelRequestXml( $expectedRequestElement->Shipper->CountryName = $countryNames[$origCountryId]; $expectedRequestElement->RegionCode = $regionCode; + if ($isProductNameContainsSpecialChars) { + $expectedRequestElement->ShipmentDetails->Pieces->Piece->PieceContents = self::PRODUCT_NAME_SPECIAL_CHARS; + } + return $expectedRequestElement->asXML(); } From 24adb1448ef850ba2127acb80ac5abfbf94f5d1c Mon Sep 17 00:00:00 2001 From: "taras.gamanov" <engcom-vendorworker-hotel@adobe.com> Date: Wed, 9 Dec 2020 17:54:30 +0200 Subject: [PATCH 225/346] MFTF has been updated --- ...teConfigurableProductWithVideoAssociatedToVariantTest.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml index 7963eecbe5224..0eb730bf91afc 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminCreateConfigurableProductWithVideoAssociatedToVariantTest.xml @@ -17,9 +17,13 @@ <severity value="MAJOR"/> <testCaseId value="MC-37344"/> <group value="ConfigurableProduct"/> + <skip> + <issueId value="MC-33903"/> + </skip> </annotations> <before> + <createData entity="ProductVideoYoutubeApiKeyConfig" stepKey="setYoutubeApiKeyConfig"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <createData entity="SimpleSubCategory" stepKey="categoryHandle"/> @@ -81,6 +85,7 @@ </before> <after> <actionGroup ref="AdminLogoutActionGroup" stepKey="amOnLogoutPage"/> + <createData entity="DefaultProductVideoConfig" stepKey="setYoutubeApiKeyDefaultConfig"/> <deleteData createDataKey="simple1Handle" stepKey="deleteSimple1"/> <deleteData createDataKey="simple2Handle" stepKey="deleteSimple2"/> <deleteData createDataKey="childProductHandle1" stepKey="deleteChild1"/> From 50535cf17ac47a384aec9af2bab22b1968869a5a Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 9 Dec 2020 17:57:48 +0200 Subject: [PATCH 226/346] MC-24840: Infinite redirect in case of backend URL is different from default website URL --- app/code/Magento/Backend/App/Area/FrontNameResolver.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Backend/App/Area/FrontNameResolver.php b/app/code/Magento/Backend/App/Area/FrontNameResolver.php index 6c586781f2d81..6f78a3d055299 100644 --- a/app/code/Magento/Backend/App/Area/FrontNameResolver.php +++ b/app/code/Magento/Backend/App/Area/FrontNameResolver.php @@ -120,10 +120,10 @@ public function getFrontName($checkHost = false) */ public function isHostBackend() { - if ($this->scopeConfig->getValue(self::XML_PATH_USE_CUSTOM_ADMIN_URL, ScopeInterface::SCOPE_STORE)) { - $backendUrl = $this->scopeConfig->getValue(self::XML_PATH_CUSTOM_ADMIN_URL, ScopeInterface::SCOPE_STORE); + if ($this->config->getValue(self::XML_PATH_USE_CUSTOM_ADMIN_URL)) { + $backendUrl = $this->config->getValue(self::XML_PATH_CUSTOM_ADMIN_URL); } else { - $backendUrl = $this->scopeConfig->getValue(Store::XML_PATH_UNSECURE_BASE_URL, ScopeInterface::SCOPE_STORE); + $backendUrl = $this->config->getValue(Store::XML_PATH_UNSECURE_BASE_URL); } $host = $this->request->getServer('HTTP_HOST', ''); return stripos($this->getHostWithPort($backendUrl), (string) $host) !== false; From a857a796df15bdb338eb4d7982c1a47fd8ee07ff Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Wed, 9 Dec 2020 22:36:07 +0200 Subject: [PATCH 227/346] =?UTF-8?q?MC-36425:=20=E2=80=9CSelect=20Shipping?= =?UTF-8?q?=20Method=E2=80=9D=20page=20of=20Multishipping=20Checkout=20is?= =?UTF-8?q?=20corrupted=20if=20a=20Customer=20use=20=E2=80=9Cgo=20back?= =?UTF-8?q?=E2=80=9D=20browser=20button=20to=20return=20to=20the=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Magento/Multishipping/Model/Cart/Controller/CartPlugin.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php b/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php index ea3e765ebb5cc..03587f71036f2 100644 --- a/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php +++ b/app/code/Magento/Multishipping/Model/Cart/Controller/CartPlugin.php @@ -74,6 +74,7 @@ public function beforeDispatch(Cart $subject, RequestInterface $request) /** @var Quote $quote */ $quote = $this->checkoutSession->getQuote(); if ($quote->isMultipleShippingAddresses() && $this->isCheckoutComplete()) { + $this->disableMultishipping->execute($quote); foreach ($quote->getAllShippingAddresses() as $address) { $quote->removeAddress($address->getId()); } From 8ba64a2f3901149a1f42a798385803d24c2e5013 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 9 Dec 2020 17:37:32 -0600 Subject: [PATCH 228/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../Magento/UrlRewrite/Model/UrlRewrite.php | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index 5f29008621c1a..0f72116ac7614 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -7,8 +7,17 @@ namespace Magento\UrlRewrite\Model; +use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Product; +use Magento\Cms\Api\PageRepositoryInterface; +use Magento\Cms\Model\Page; use Magento\Framework\App\ObjectManager; +use Magento\Framework\EntityManager\EventManager; +use Magento\Framework\Indexer\CacheContext; use Magento\Framework\Serialize\Serializer\Json; +use Magento\UrlRewrite\Controller\Adminhtml\Url\Rewrite; /** * UrlRewrite model class @@ -92,4 +101,58 @@ public function setMetadata($metadata) } return $this->setData(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::METADATA, $metadata); } + + private function opt1() { + $map = [ + Rewrite::ENTITY_TYPE_PRODUCT => Product::CACHE_TAG, + Rewrite::ENTITY_TYPE_CATEGORY => Category::CACHE_TAG, + Rewrite::ENTITY_TYPE_CMS_PAGE => Page::CACHE_TAG + ]; + + if ($this->getEntityType() !== Rewrite::ENTITY_TYPE_CUSTOM) { + $cacheKey = $map[$this->getEntityType()]; + + $cacheContext = ObjectManager::getInstance()->get(CacheContext::class); + $eventManager = ObjectManager::getInstance()->get(EventManager::class); + + $cacheContext->registerEntities($cacheKey, [$this->getEntityId()]); + $eventManager->dispatch('clean_cache_by_tags', ['object' => $cacheContext]); + } + } + + private function opt2() { + $map = [ + Rewrite::ENTITY_TYPE_PRODUCT => function ($prodId) { + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); + return $productRepository->getById($prodId); + }, + Rewrite::ENTITY_TYPE_CATEGORY => function ($catId) { + /** @var CategoryRepositoryInterface $productRepository */ + $categoryRepository = ObjectManager::getInstance()->get(CategoryRepositoryInterface::class); + return $categoryRepository->get($catId); + }, + Rewrite::ENTITY_TYPE_CMS_PAGE => function ($cmsId) { + /** @var PageRepositoryInterface $productRepository */ + $pageRepository = ObjectManager::getInstance()->get(PageRepositoryInterface::class); + return $pageRepository->getById($cmsId); + }, + Rewrite::ENTITY_TYPE_CUSTOM => false + ]; + + $getter = $map[$this->getEntityType()]; + + if ($getter) { + $entity = $getter($this->getEntityId()); + + $entityManager = ObjectManager::getInstance()->get(EventManager::class); + $entityManager->dispatch('clean_cache_by_tags', ['object' => $entity]); + } + } + + public function afterSave() + { + $this->opt1(); + return parent::afterSave(); // TODO: Change the autogenerated stub + } } From c33bb8ea7679bc069bb857ad469b09c3bc8c2680 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Thu, 10 Dec 2020 07:21:21 +0200 Subject: [PATCH 229/346] =?UTF-8?q?MC-36425:=20=E2=80=9CSelect=20Shipping?= =?UTF-8?q?=20Method=E2=80=9D=20page=20of=20Multishipping=20Checkout=20is?= =?UTF-8?q?=20corrupted=20if=20a=20Customer=20use=20=E2=80=9Cgo=20back?= =?UTF-8?q?=E2=80=9D=20browser=20button=20to=20return=20to=20the=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...oginAsCustomerMultishippingLoggingTest.xml | 13 ++-- ...teToShippingInformationPageActionGroup.xml | 20 +++++ ...MultipleAddressesOnCheckoutActionGroup.xml | 29 +++++++ ...toreFrontCheckingWithMultishipmentTest.xml | 2 +- ...oreFrontCheckingWithSingleShipmentTest.xml | 2 +- ...toreFrontMinicartWithMultishipmentTest.xml | 2 +- ...hMultishippingAfterReturningToCartTest.xml | 78 +++++++++++++++++++ .../StorefrontOrderWithMultishippingTest.xml | 8 +- ...heckMoneyOrderPaymentMethodActionGroup.xml | 18 +++++ ...heckMoneyOrderPaymentMethodActionGroup.xml | 18 +++++ ...sableFlatRateShippingMethodActionGroup.xml | 18 +++++ ...liDisableFreeShippingMethodActionGroup.xml | 18 +++++ ...nableFlatRateShippingMethodActionGroup.xml | 18 +++++ ...CliEnableFreeShippingMethodActionGroup.xml | 18 +++++ ...ontPaypalSmartButtonInCheckoutPageTest.xml | 2 +- 15 files changed, 251 insertions(+), 13 deletions(-) create mode 100644 app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontNavigateToShippingInformationPageActionGroup.xml create mode 100644 app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontSelectMultipleAddressesOnCheckoutActionGroup.xml create mode 100644 app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCreateOrderWithMultishippingAfterReturningToCartTest.xml create mode 100644 app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliDisableCheckMoneyOrderPaymentMethodActionGroup.xml create mode 100644 app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliEnableCheckMoneyOrderPaymentMethodActionGroup.xml create mode 100644 app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFlatRateShippingMethodActionGroup.xml create mode 100644 app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFreeShippingMethodActionGroup.xml create mode 100644 app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFlatRateShippingMethodActionGroup.xml create mode 100644 app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFreeShippingMethodActionGroup.xml diff --git a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml index 79c7571a08cfb..79a224c4f4bc6 100644 --- a/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml +++ b/app/code/Magento/LoginAsCustomer/Test/Mftf/Test/AdminLoginAsCustomerMultishippingLoggingTest.xml @@ -23,14 +23,17 @@ </annotations> <before> - <magentoCLI command="config:set {{EnableFreeShippingMethod.path}} {{EnableFreeShippingMethod.value}}" stepKey="enableFreeShipping"/> - <magentoCLI command="config:set {{EnableFlatRateShippingMethod.path}} {{EnableFlatRateShippingMethod.value}}" stepKey="enableFlatRateShipping"/> - <magentoCLI command="config:set {{EnableCheckMoneyOrderPaymentMethod.path}} {{EnableCheckMoneyOrderPaymentMethod.value}}" stepKey="enableCheckMoneyOrderPaymentMethod"/> + <actionGroup ref="CliEnableFreeShippingMethodActionGroup" stepKey="enableFreeShipping"/> + <actionGroup ref="CliEnableFlatRateShippingMethodActionGroup" stepKey="enableFlatRateShipping"/> + <actionGroup ref="CliEnableCheckMoneyOrderPaymentMethodActionGroup" stepKey="enableCheckMoneyOrderPaymentMethod"/> <magentoCLI command="config:set {{LoginAsCustomerConfigDataEnabled.path}} 1" stepKey="enableLoginAsCustomer"/> <magentoCLI command="config:set {{LoginAsCustomerStoreViewLogin.path}} 0" stepKey="enableLoginAsCustomerAutoDetection"/> - <magentoCLI command="cache:flush config" stepKey="flushCacheBeforeTestRun"/> + <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCacheBeforeTestRun"> + <argument name="tags" value="config"/> + </actionGroup> + <createData entity="SimpleProduct2" stepKey="createProduct1"/> <createData entity="SimpleProduct2" stepKey="createProduct2"/> <createData entity="Simple_US_Customer_Assistance_Allowed_Two_Addresses" stepKey="createCustomer"/> @@ -43,7 +46,7 @@ <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearAllOrdersGridFilters"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="adminLogout"/> - <magentoCLI command="config:set {{DisableFreeShippingMethod.path}} {{DisableFreeShippingMethod.value}}" stepKey="disableFreeShipping"/> + <actionGroup ref="CliDisableFreeShippingMethodActionGroup" stepKey="disableFreeShipping"/> <magentoCLI command="cache:flush config" stepKey="flushCacheAfterTestRun"/> </after> diff --git a/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontNavigateToShippingInformationPageActionGroup.xml b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontNavigateToShippingInformationPageActionGroup.xml new file mode 100644 index 0000000000000..1ca3b20af6a84 --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontNavigateToShippingInformationPageActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontNavigateToShippingInformationPageActionGroup"> + <annotations> + <description>Navigate to shipping information page. Starts on multishipping addressees page.</description> + </annotations> + + <waitForElementVisible selector="{{SingleShippingSection.goToShippingInfo}}" stepKey="waitForButton"/> + <click selector="{{SingleShippingSection.goToShippingInfo}}" stepKey="goToShippingInformation"/> + <waitForPageLoad stepKey="waitForShippingInfoPage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontSelectMultipleAddressesOnCheckoutActionGroup.xml b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontSelectMultipleAddressesOnCheckoutActionGroup.xml new file mode 100644 index 0000000000000..f5e76a0d146fc --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/ActionGroup/StorefrontSelectMultipleAddressesOnCheckoutActionGroup.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontSelectMultipleAddressesOnCheckoutActionGroup"> + <annotations> + <description>Select addresses for multinshipping checkout. Start on multishipping addresses page.</description> + </annotations> + <arguments> + <argument name="addressOption1" type="string" defaultValue="1"/> + <argument name="addressOption2" type="string" defaultValue="2"/> + </arguments> + + <waitForElementVisible selector="{{MultishippingSection.shippingAddressOptions(addressOption1,addressOption1)}}" stepKey="waitForMultishippingPage"/> + <grabTextFrom selector="{{MultishippingSection.shippingAddressOptions(addressOption1,addressOption1)}}" stepKey="firstShippingAddressValue"/> + <selectOption selector="{{MultishippingSection.shippingAddressSelector(addressOption1)}}" userInput="{$firstShippingAddressValue}" stepKey="selectFirstShippingMethod"/> + <waitForPageLoad after="selectFirstShippingMethod" stepKey="waitForSecondShippingAddresses"/> + <grabTextFrom selector="{{MultishippingSection.shippingAddressOptions(addressOption2,addressOption2)}}" stepKey="secondShippingAddressValue"/> + <selectOption selector="{{MultishippingSection.shippingAddressSelector(addressOption2)}}" userInput="{$secondShippingAddressValue}" stepKey="selectSecondShippingMethod"/> + <click selector="{{SingleShippingSection.updateAddress}}" stepKey="clickOnUpdateAddress"/> + <waitForPageLoad stepKey="waitForShippingInformation"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithMultishipmentTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithMultishipmentTest.xml index 7ae23e8f871eb..5e1c14c57f533 100644 --- a/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithMultishipmentTest.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithMultishipmentTest.xml @@ -30,7 +30,7 @@ <createData entity="Simple_US_Customer_Two_Addresses" stepKey="customer"/> <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShipping"/> <createData entity="FlatRateShippingMethodConfig" stepKey="enableFlatRateShipping"/> - <magentoCLI command="config:set {{EnableCheckMoneyOrderPaymentMethod.path}} {{EnableCheckMoneyOrderPaymentMethod.value}}" stepKey="enableCheckMoneyOrderPaymentMethod"/> + <actionGroup ref="CliEnableCheckMoneyOrderPaymentMethodActionGroup" stepKey="enableCheckMoneyOrderPaymentMethod"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> <argument name="Customer" value="$$customer$$"/> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithSingleShipmentTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithSingleShipmentTest.xml index 27876df8caefe..dcdc9203a2075 100644 --- a/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithSingleShipmentTest.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontCheckingWithSingleShipmentTest.xml @@ -30,7 +30,7 @@ <createData entity="Simple_US_Customer_Two_Addresses" stepKey="customer"/> <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShipping"/> <createData entity="FlatRateShippingMethodConfig" stepKey="enableFlatRateShipping"/> - <magentoCLI command="config:set {{EnableCheckMoneyOrderPaymentMethod.path}} {{EnableCheckMoneyOrderPaymentMethod.value}}" stepKey="enableCheckMoneyOrderPaymentMethod"/> + <actionGroup ref="CliEnableCheckMoneyOrderPaymentMethodActionGroup" stepKey="enableCheckMoneyOrderPaymentMethod"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> <argument name="Customer" value="$$customer$$"/> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontMinicartWithMultishipmentTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontMinicartWithMultishipmentTest.xml index f21a8d32d8841..043d0fc41abe7 100644 --- a/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontMinicartWithMultishipmentTest.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StoreFrontMinicartWithMultishipmentTest.xml @@ -30,7 +30,7 @@ <createData entity="Simple_US_Customer_Two_Addresses" stepKey="customer"/> <createData entity="FreeShippinMethodConfig" stepKey="enableFreeShipping"/> <createData entity="FlatRateShippingMethodConfig" stepKey="enableFlatRateShipping"/> - <magentoCLI command="config:set {{EnableCheckMoneyOrderPaymentMethod.path}} {{EnableCheckMoneyOrderPaymentMethod.value}}" stepKey="enableCheckMoneyOrderPaymentMethod"/> + <actionGroup ref="CliEnableCheckMoneyOrderPaymentMethodActionGroup" stepKey="enableCheckMoneyOrderPaymentMethod"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> <argument name="Customer" value="$$customer$$"/> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCreateOrderWithMultishippingAfterReturningToCartTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCreateOrderWithMultishippingAfterReturningToCartTest.xml new file mode 100644 index 0000000000000..f0a97d240aa69 --- /dev/null +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontCreateOrderWithMultishippingAfterReturningToCartTest.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontCreateOrderWithMultishippingAfterReturningToCartTest"> + <annotations> + <features value="Multishipping"/> + <stories value="Checkout with multiple addresses."/> + <title value="Checkout with multiple addresses after returning on cart page during checkout."/> + <description value="Verify customer able to checkout with multiple addresses after returning to cart page and continue checkout with browser 'back' button."/> + <severity value="AVERAGE"/> + <testCaseId value="MC-39583"/> + <useCaseId value="MC-36425"/> + <group value="multishipping"/> + </annotations> + + <before> + <!--Create test data.--> + <createData entity="SimpleProduct2" stepKey="product"/> + <createData entity="Simple_US_Customer_Two_Addresses" stepKey="customer"/> + <!--Set up configuration.--> + <actionGroup ref="CliEnableFreeShippingMethodActionGroup" stepKey="enableFreeShipping"/> + <actionGroup ref="CliEnableFlatRateShippingMethodActionGroup" stepKey="enableFlatRateShipping"/> + <actionGroup ref="CliEnableCheckMoneyOrderPaymentMethodActionGroup" stepKey="enableCheckMoneyOrderPaymentMethod"/> + </before> + + <after> + <!--Clean up test data, revert configuration.--> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogoutStorefront"/> + <deleteData createDataKey="customer" stepKey="deleteCustomer"/> + <actionGroup ref="CliDisableFreeShippingMethodActionGroup" stepKey="disableFreeShipping"/> + </after> + + <!--Add product to cart and proceed to multishipping checkout. --> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> + <argument name="Customer" value="$$customer$$"/> + </actionGroup> + <actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="navigateToProductPage"> + <argument name="productUrl" value="$product.custom_attributes[url_key]$"/> + </actionGroup> + <actionGroup ref="AddProductWithQtyToCartFromStorefrontProductPageActionGroup" stepKey="addProductToCart"> + <argument name="productName" value="$product.name$"/> + <argument name="productQty" value="2"/> + </actionGroup> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="openCart"/> + <actionGroup ref="CheckingWithMultipleAddressesActionGroup" stepKey="checkoutWithMultipleAddresses"/> + <actionGroup ref="SelectMultiShippingInfoActionGroup" stepKey="checkoutWithMultipleShipping"/> + <waitForPageLoad stepKey="waitForShippingInfoPage"/> + <!--Open cart page before place order.--> + <actionGroup ref="StorefrontCartPageOpenActionGroup" stepKey="navigateToCartPage"/> + <waitForPageLoad stepKey="waitForCartPageLoad"/> + <!--Go back to continue checkout with multiple addresses again.--> + <moveBack stepKey="navigateBackToMultishippingCheckout"/> + <actionGroup ref="StorefrontSelectMultipleAddressesOnCheckoutActionGroup" stepKey="selectAddresses"/> + <actionGroup ref="StorefrontNavigateToShippingInformationPageActionGroup" stepKey="navigateToShippingInformationPage"/> + <actionGroup ref="SelectMultiShippingInfoActionGroup" stepKey="checkoutWithMultipleShippingAgain"/> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyPaymentAgain"/> + <actionGroup ref="SelectBillingInfoActionGroup" stepKey="checkoutWithPaymentMethodAgain"/> + <actionGroup ref="ReviewOrderForMultiShipmentActionGroup" stepKey="reviewOrderForMultiShipment"> + <argument name="totalNameForFirstOrder" value="Shipping & Handling"/> + <argument name="totalPositionForFirstOrder" value="1"/> + <argument name="totalNameForSecondOrder" value="Shipping & Handling"/> + <argument name="totalPositionForSecondOrder" value="2"/> + </actionGroup> + <waitForPageLoad stepKey="waitForPlaceOrderPageLoad"/> + <actionGroup ref="StorefrontPlaceOrderForMultipleAddressesActionGroup" stepKey="placeOrder"> + <argument name="firstOrderPosition" value="1"/> + <argument name="secondOrderPosition" value="2"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml index 2e5c0acc32053..cdf9c5683c57b 100644 --- a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontOrderWithMultishippingTest.xml @@ -27,9 +27,9 @@ <createData entity="SimpleProduct2" stepKey="createProduct2"/> <createData entity="Simple_US_Customer_Two_Addresses" stepKey="createCustomer"/> <!-- Set configurations --> - <magentoCLI command="config:set {{EnableFreeShippingMethod.path}} {{EnableFreeShippingMethod.value}}" stepKey="enableFreeShipping"/> - <magentoCLI command="config:set {{EnableFlatRateShippingMethod.path}} {{EnableFlatRateShippingMethod.value}}" stepKey="enableFlatRateShipping"/> - <magentoCLI command="config:set {{EnableCheckMoneyOrderPaymentMethod.path}} {{EnableCheckMoneyOrderPaymentMethod.value}}" stepKey="enableCheckMoneyOrderPaymentMethod"/> + <actionGroup ref="CliEnableFreeShippingMethodActionGroup" stepKey="enableFreeShipping"/> + <actionGroup ref="CliEnableFlatRateShippingMethodActionGroup" stepKey="enableFlatRateShipping"/> + <actionGroup ref="CliEnableCheckMoneyOrderPaymentMethodActionGroup" stepKey="enableCheckMoneyOrderPaymentMethod"/> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefrontAccount"> <argument name="Customer" value="$$createCustomer$$"/> @@ -42,7 +42,7 @@ <!-- Need logout before customer delete. Fatal error appears otherwise --> <actionGroup ref="StorefrontCustomerLogoutActionGroup" stepKey="customerLogout"/> <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> - <magentoCLI command="config:set {{DisableFreeShippingMethod.path}} {{DisableFreeShippingMethod.value}}" stepKey="disableFreeShipping"/> + <actionGroup ref="CliDisableFreeShippingMethodActionGroup" stepKey="disableFreeShipping"/> <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearAllOrdersGridFilters"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </after> diff --git a/app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliDisableCheckMoneyOrderPaymentMethodActionGroup.xml b/app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliDisableCheckMoneyOrderPaymentMethodActionGroup.xml new file mode 100644 index 0000000000000..4189a28e6746a --- /dev/null +++ b/app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliDisableCheckMoneyOrderPaymentMethodActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="CliDisableCheckMoneyOrderPaymentMethodActionGroup"> + <annotations> + <description>Disable Check/Money order payment method by CLI command config:set</description> + </annotations> + + <magentoCLI command="config:set {{DisableCheckMoneyOrderPaymentMethod.path}} {{DisableCheckMoneyOrderPaymentMethod.value}}" stepKey="disableCheckMoneyOrderPaymentMethod"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliEnableCheckMoneyOrderPaymentMethodActionGroup.xml b/app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliEnableCheckMoneyOrderPaymentMethodActionGroup.xml new file mode 100644 index 0000000000000..155633b0772fd --- /dev/null +++ b/app/code/Magento/OfflinePayments/Test/Mftf/ActionGroup/CliEnableCheckMoneyOrderPaymentMethodActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="CliEnableCheckMoneyOrderPaymentMethodActionGroup"> + <annotations> + <description>Enable Check/Money order payment method by CLI command config:set</description> + </annotations> + + <magentoCLI command="config:set {{EnableCheckMoneyOrderPaymentMethod.path}} {{EnableCheckMoneyOrderPaymentMethod.value}}" stepKey="enableCheckMoneyOrderPaymentMethod"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFlatRateShippingMethodActionGroup.xml b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFlatRateShippingMethodActionGroup.xml new file mode 100644 index 0000000000000..3b3e3d597e9f7 --- /dev/null +++ b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFlatRateShippingMethodActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="CliDisableFlatRateShippingMethodActionGroup"> + <annotations> + <description>Disable Flat Rate shipping method by CLI command config:set</description> + </annotations> + + <magentoCLI command="config:set {{DisableFlatRateShippingMethod.path}} {{DisableFlatRateShippingMethod.value}}" stepKey="disableFlatRateShippingMethod"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFreeShippingMethodActionGroup.xml b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFreeShippingMethodActionGroup.xml new file mode 100644 index 0000000000000..38f2176a95986 --- /dev/null +++ b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliDisableFreeShippingMethodActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="CliDisableFreeShippingMethodActionGroup"> + <annotations> + <description>Disable Free Shipping method by CLI command config:set</description> + </annotations> + + <magentoCLI command="config:set {{DisableFreeShippingMethod.path}} {{DisableFreeShippingMethod.value}}" stepKey="disableFreeShippingMethod"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFlatRateShippingMethodActionGroup.xml b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFlatRateShippingMethodActionGroup.xml new file mode 100644 index 0000000000000..f138a9b616289 --- /dev/null +++ b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFlatRateShippingMethodActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="CliEnableFlatRateShippingMethodActionGroup"> + <annotations> + <description>Enable Flat Rate shipping method by CLI command config:set</description> + </annotations> + + <magentoCLI command="config:set {{EnableFlatRateShippingMethod.path}} {{EnableFlatRateShippingMethod.value}}" stepKey="enableFlatRateShippingMethod"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFreeShippingMethodActionGroup.xml b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFreeShippingMethodActionGroup.xml new file mode 100644 index 0000000000000..05b7378466b6f --- /dev/null +++ b/app/code/Magento/OfflineShipping/Test/Mftf/ActionGroup/CliEnableFreeShippingMethodActionGroup.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="CliEnableFreeShippingMethodActionGroup"> + <annotations> + <description>Enable Free Shipping method by CLI command config:set</description> + </annotations> + + <magentoCLI command="config:set {{EnableFreeShippingMethod.path}} {{EnableFreeShippingMethod.value}}" stepKey="enableFreeShippingMethod"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonInCheckoutPageTest.xml b/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonInCheckoutPageTest.xml index cea228ac7a344..d43e894b014ff 100644 --- a/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonInCheckoutPageTest.xml +++ b/app/code/Magento/Paypal/Test/Mftf/Test/StorefrontPaypalSmartButtonInCheckoutPageTest.xml @@ -41,7 +41,7 @@ <after> <magentoCLI command="config:set {{StorefrontPaypalEnableTransferCartLineConfigData.path}} {{StorefrontPaypalEnableTransferCartLineConfigData.value}}" stepKey="enableTransferCartLine"/> <magentoCLI command="config:set {{StorefrontPaypalExpressAuthorizationPaymentActionOptionConfigData.path}} {{StorefrontPaypalExpressAuthorizationPaymentActionOptionConfigData.value}}" stepKey="setPaymentAction"/> - <magentoCLI command="config:set {{DisableFreeShippingMethod.path}} {{DisableFreeShippingMethod.value}}" stepKey="disableFreeShipping"/> + <actionGroup ref="CliDisableFreeShippingMethodActionGroup" stepKey="disableFreeShipping"/> <!-- Delete product --> <deleteData stepKey="deleteCategory" createDataKey="createCategory"/> <deleteData stepKey="deleteProduct" createDataKey="createProduct"/> From 706e63d8995daedacdfcb42dc1c7de700e8f1eb2 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 10 Dec 2020 10:38:37 +0200 Subject: [PATCH 230/346] renamed Action Groups --- ...=> AssertAdminManageStockOnEditPageActionGroup.xml} | 2 +- ...=> AssertAdminProductInfoOnEditPageActionGroup.xml} | 2 +- ...ertAdminProductIsAssignedToCategoryActionGroup.xml} | 2 +- ...rontProductStockStatusOnProductPageActionGroup.xml} | 2 +- ...ctWithRegularPriceInStockEnabledFlatCatalogTest.xml | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-) rename app/code/Magento/Catalog/Test/Mftf/ActionGroup/{AdminAssertManageStockOnEditPageActionGroup.xml => AssertAdminManageStockOnEditPageActionGroup.xml} (92%) rename app/code/Magento/Catalog/Test/Mftf/ActionGroup/{AdminAssertProductInfoOnEditPageActionGroup.xml => AssertAdminProductInfoOnEditPageActionGroup.xml} (97%) rename app/code/Magento/Catalog/Test/Mftf/ActionGroup/{AdminAssertProductIsAssignedToCategoryActionGroup.xml => AssertAdminProductIsAssignedToCategoryActionGroup.xml} (92%) rename app/code/Magento/Catalog/Test/Mftf/ActionGroup/{StorefrontAssertProductStockStatusOnProductPageActionGroup.xml => AssertStorefrontProductStockStatusOnProductPageActionGroup.xml} (93%) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminManageStockOnEditPageActionGroup.xml similarity index 92% rename from app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml rename to app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminManageStockOnEditPageActionGroup.xml index 67df650a24228..eca989a5de41f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertManageStockOnEditPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminManageStockOnEditPageActionGroup.xml @@ -8,7 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminAssertManageStockOnEditPageActionGroup"> + <actionGroup name="AssertAdminManageStockOnEditPageActionGroup"> <annotations> <description>Check if manageStock value is correct (the Product Edit page->Advanced Inventory section should be opened in Admin prior this check).</description> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductInfoOnEditPageActionGroup.xml similarity index 97% rename from app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml rename to app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductInfoOnEditPageActionGroup.xml index ba67168958fca..d91cdfee0489c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductInfoOnEditPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductInfoOnEditPageActionGroup.xml @@ -8,7 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminAssertProductInfoOnEditPageActionGroup"> + <actionGroup name="AssertAdminProductInfoOnEditPageActionGroup"> <annotations> <description>Validates next fields on the Product Edit Page: name, sku, price, quantity, stock status, tax class, weight, weigh select, visibility, url key</description> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductIsAssignedToCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductIsAssignedToCategoryActionGroup.xml similarity index 92% rename from app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductIsAssignedToCategoryActionGroup.xml rename to app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductIsAssignedToCategoryActionGroup.xml index b33e319adc1f4..e6b178937a2cc 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminAssertProductIsAssignedToCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductIsAssignedToCategoryActionGroup.xml @@ -8,7 +8,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminAssertProductIsAssignedToCategoryActionGroup"> + <actionGroup name="AssertAdminProductIsAssignedToCategoryActionGroup"> <annotations> <description>Checks if product is assigned to category (the Product Edit page should be opened in Admin prior this check).</description> </annotations> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductStockStatusOnProductPageActionGroup.xml similarity index 93% rename from app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml rename to app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductStockStatusOnProductPageActionGroup.xml index 5af46bcd734d1..857d88ebc197c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAssertProductStockStatusOnProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertStorefrontProductStockStatusOnProductPageActionGroup.xml @@ -7,7 +7,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="StorefrontAssertProductStockStatusOnProductPageActionGroup"> + <actionGroup name="AssertStorefrontProductStockStatusOnProductPageActionGroup"> <annotations> <description>Validates that the provided Product Stock Status is present and correct (the Product Detail page should be opened on Storefront prior this check)</description> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml index c083f827e8930..3af6de07e561d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml @@ -67,20 +67,20 @@ </actionGroup> <actionGroup ref="AdminClickOnAdvancedInventoryLinkActionGroup" stepKey="clickTheAdvancedInventoryLink1"/> - <actionGroup ref="AdminAssertManageStockOnEditPageActionGroup" stepKey="assertManageStock1"> + <actionGroup ref="AssertAdminManageStockOnEditPageActionGroup" stepKey="assertManageStock1"> <argument name="manageStock" value="No"/> </actionGroup> <actionGroup ref="AdminSubmitAdvancedInventoryFormActionGroup" stepKey="clickDoneButtonOnAdvancedInventorySection1"/> - <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToInitialCategory"> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToInitialCategory"> <argument name="categoryName" value="$$initialCategoryEntity.name$$"/> </actionGroup> - <actionGroup ref="AdminAssertProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToCategoryTwo"> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="checkifProductIsAssignedToCategoryTwo"> <argument name="categoryName" value="$$categoryEntity.name$$"/> </actionGroup> - <actionGroup ref="AdminAssertProductInfoOnEditPageActionGroup" stepKey="assertProductInfo"> + <actionGroup ref="AssertAdminProductInfoOnEditPageActionGroup" stepKey="assertProductInfo"> <argument name="product" value="simpleProductEnabledFlat"/> </actionGroup> @@ -105,7 +105,7 @@ <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeSimpleProductSKUOnStoreFrontPage"> <argument name="productSku" value="{{simpleProductEnabledFlat.sku}}"/> </actionGroup> - <actionGroup ref="StorefrontAssertProductStockStatusOnProductPageActionGroup" stepKey="seeSimpleProductStockStatusOnStoreFrontPage"> + <actionGroup ref="AssertStorefrontProductStockStatusOnProductPageActionGroup" stepKey="seeSimpleProductStockStatusOnStoreFrontPage"> <argument name="productStockStatus" value="{{simpleProductEnabledFlat.storefrontStatus}}"/> </actionGroup> From 1b11a71ff1a141c1d58b651f2cdeefabffd4f6bd Mon Sep 17 00:00:00 2001 From: "taras.gamanov" <engcom-vendorworker-hotel@adobe.com> Date: Thu, 10 Dec 2020 12:03:21 +0200 Subject: [PATCH 231/346] refactoring --- .../Block/Plugin/Product/Media/Gallery.php | 4 ++-- .../Test/Unit/Block/Plugin/Product/Media/GalleryTest.php | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php b/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php index 21bfb3b873a7b..c000e52aae39a 100644 --- a/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php +++ b/app/code/Magento/ConfigurableProduct/Block/Plugin/Product/Media/Gallery.php @@ -56,7 +56,7 @@ public function afterGetOptionsMediaGalleryDataJson( * @param Product $product * @return array */ - private function getProductGallery($product) + private function getProductGallery(Product $product): array { $result = []; $images = $this->getImagesOrderedByPosition($product); @@ -74,7 +74,7 @@ private function getProductGallery($product) * @param Product $product * @return array */ - private function getImagesOrderedByPosition($product) + private function getImagesOrderedByPosition(Product $product): array { $imagesCollection = $product->getMediaGalleryImages(); $images = $imagesCollection->getItems(); diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php index 367b639176665..7debc86c9ed23 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Plugin/Product/Media/GalleryTest.php @@ -46,8 +46,6 @@ public function testAfterGetOptions() ->disableOriginalConstructor() ->onlyMethods(['getItems']) ->getMock(); - - $galleryMock->expects(($this->any()))->method('getProduct')->willReturn($productMock); $productMock->expects($this->once())->method('getTypeId')->willReturn('configurable'); $productMock->expects($this->once())->method('getTypeInstance')->willReturn($configurableTypeMock); From 2c4d9b1f0604d2462ea4d231168e8783ce226ff4 Mon Sep 17 00:00:00 2001 From: Sergio Vera <svera@adobe.com> Date: Thu, 10 Dec 2020 11:35:58 +0100 Subject: [PATCH 232/346] MC-39542: : Change LiveCodeTest php stability test - Return error if not PHP supported versions are defined in composer.json --- dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php index f294e2c2f55e1..65358cd785066 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Php/LiveCodeTest.php @@ -414,6 +414,7 @@ public function testStrictTypes() public function testPhpCompatibility() { $targetVersions = $this->getTargetPhpVersions(); + $this->assertNotEmpty($targetVersions, 'No supported versions information in composer.json'); $reportFile = self::$reportDir . '/phpcompatibility_report.txt'; $rulesetDir = __DIR__ . '/_files/PHPCompatibilityMagento'; From e85f913ce5e87bcdef7bf265b5b7e04c4b060535 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 10 Dec 2020 13:05:20 +0200 Subject: [PATCH 233/346] adding AssertAdminProductIsAssignedToCategoryActionGroup --- ...ProductIsAssignedToCategoryActionGroup.xml | 22 +++++++++++++++++++ .../AdminProductFormSection.xml | 1 + ...dminUpdateSimpleProductTieredPriceTest.xml | 8 +++++-- ...PriceInStockNotVisibleIndividuallyTest.xml | 8 +++++-- ...ceInStockVisibleInCatalogAndSearchTest.xml | 8 +++++-- ...arPriceInStockVisibleInCatalogOnlyTest.xml | 8 +++++-- ...larPriceInStockVisibleInSearchOnlyTest.xml | 8 +++++-- ...gularPriceInStockWithCustomOptionsTest.xml | 8 +++++-- ...eProductWithRegularPriceOutOfStockTest.xml | 8 +++++-- 9 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductIsAssignedToCategoryActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductIsAssignedToCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductIsAssignedToCategoryActionGroup.xml new file mode 100644 index 0000000000000..e6b178937a2cc --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AssertAdminProductIsAssignedToCategoryActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertAdminProductIsAssignedToCategoryActionGroup"> + <annotations> + <description>Checks if product is assigned to category (the Product Edit page should be opened in Admin prior this check).</description> + </annotations> + <arguments> + <argument name="categoryName" type="string"/> + </arguments> + + <seeElement selector="{{AdminProductFormSection.categories(categoryName)}}" stepKey="seeCategoryName"/> + + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml index 1ca051e2f6669..d70c48f2b00e3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormSection/AdminProductFormSection.xml @@ -77,5 +77,6 @@ <element name="newAddedAttribute" type="text" selector="//fieldset[@class='admin__fieldset']//div[contains(@data-index,'{{attributeCode}}')]" parameterized="true"/> <element name="newCategoryButton" type="button" selector="button[data-index='create_category_button']" timeout="30"/> <element name="footerBlock" type="block" selector="//footer"/> + <element name="categories" type="text" selector="//*[@class='admin__action-multiselect-crumb']/span[contains(text(), '{{categoryName}}')]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml index 300b312612253..338df481e3794 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml @@ -110,8 +110,12 @@ <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductTierPrice300InStock.status}}" stepKey="seeSimpleProductStockStatus"/> <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductTierPrice300InStock.weight}}" stepKey="seeSimpleProductWeight"/> <seeInField selector="{{AdminProductFormSection.productWeightSelect}}" userInput="{{simpleProductTierPrice300InStock.weightSelect}}" stepKey="seeSimpleProductWeightSelect"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="seeSelectedCategories"/> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickCategoriesDropDownToVerify"/> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="seeSelectedCategories"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> <seeInField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{simpleProductTierPrice300InStock.urlKey}}" stepKey="seeUrlKey"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml index 86fac835ce44d..3d53501ede4cc 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml @@ -84,8 +84,12 @@ <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductNotVisibleIndividually.quantity}}" stepKey="seeSimpleProductQuantity"/> <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductNotVisibleIndividually.status}}" stepKey="seeSimpleProductStockStatus"/> <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductNotVisibleIndividually.weightNoDecimals}}" stepKey="seeSimpleProductWeight"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="seeSelectedCategories" /> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickCategoriesDropDownToVerify"/> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="seeSelectedCategories"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + <seeInField selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductNotVisibleIndividually.visibility}}" stepKey="seeSimpleProductVisibility"/> <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection"/> <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSectionHeader"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml index 320edba5feeff..e121e239ad334 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml @@ -84,8 +84,12 @@ <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductRegularPrice245InStock.quantity}}" stepKey="seeSimpleProductQuantity"/> <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductRegularPrice245InStock.status}}" stepKey="seeSimpleProductStockStatus"/> <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductRegularPrice245InStock.weight}}" stepKey="seeSimpleProductWeight"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="selectedCategories" /> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickCategoriesDropDownToVerify"/> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="selectedCategories"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + <seeInField selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductRegularPrice245InStock.visibility}}" stepKey="seeVisibility"/> <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml index 77c3e7548a3cf..6ad01e59eea51 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml @@ -84,8 +84,12 @@ <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductRegularPrice32501InStock.quantity}}" stepKey="seeSimpleProductQuantity"/> <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductRegularPrice32501InStock.status}}" stepKey="seeSimpleProductStockStatus"/> <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductRegularPrice32501InStock.weight}}" stepKey="seeSimpleProductWeight"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="selectedCategories" /> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickCategoriesDropDownToVerify"/> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="selectedCategories"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + <seeInField selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductRegularPrice32501InStock.visibility}}" stepKey="seeVisibility"/> <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml index 39dab0b08915c..ec4b0296e82c1 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml @@ -84,8 +84,12 @@ <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductRegularPrice325InStock.quantity}}" stepKey="seeSimpleProductQuantity"/> <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductRegularPrice325InStock.status}}" stepKey="seeSimpleProductStockStatus"/> <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductRegularPrice325InStock.weight}}" stepKey="seeSimpleProductWeight"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="selectedCategories" /> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickCategoriesDropDownToVerify"/> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="selectedCategories"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + <seeInField selector="{{AdminProductFormSection.visibility}}" userInput="{{simpleProductRegularPrice325InStock.visibility}}" stepKey="seeVisibility"/> <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml index 670030d1d98ea..2a7d5c6c18a02 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml @@ -97,8 +97,12 @@ <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductRegularPriceCustomOptions.quantity}}" stepKey="seeSimpleProductQuantity"/> <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductRegularPriceCustomOptions.status}}" stepKey="seeSimpleProductStockStatus"/> <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductRegularPriceCustomOptions.weight}}" stepKey="seeSimpleProductWeight"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="selectedCategories" /> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickCategoriesDropDownToVerify"/> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="selectedCategories"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> <seeInField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{simpleProductRegularPriceCustomOptions.urlKey}}" stepKey="seeUrlKey"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml index 441bc9b8f8005..170e731f38ba3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml @@ -84,8 +84,12 @@ <seeInField selector="{{AdminProductFormSection.productQuantity}}" userInput="{{simpleProductRegularPrice32503OutOfStock.quantity}}" stepKey="seeSimpleProductQuantity"/> <seeInField selector="{{AdminProductFormSection.productStockStatus}}" userInput="{{simpleProductRegularPrice32503OutOfStock.status}}" stepKey="seeSimpleProductStockStatus"/> <seeInField selector="{{AdminProductFormSection.productWeight}}" userInput="{{simpleProductRegularPrice32503OutOfStock.weight}}" stepKey="seeSimpleProductWeight"/> - <click selector="{{AdminProductFormSection.categoriesDropdown}}" stepKey="clickCategoriesDropDownToVerify"/> - <see selector="{{AdminProductFormSection.selectMultipleCategories}}" userInput="$$categoryEntity.name$$" stepKey="selectedCategories" /> + + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="clickCategoriesDropDownToVerify"/> + <actionGroup ref="AssertAdminProductIsAssignedToCategoryActionGroup" stepKey="selectedCategories"> + <argument name="categoryName" value="$$categoryEntity.name$$"/> + </actionGroup> + <scrollTo selector="{{AdminProductSEOSection.sectionHeader}}" x="0" y="-80" stepKey="scrollToAdminProductSEOSection1"/> <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="clickAdminProductSEOSection1"/> <seeInField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="{{simpleProductRegularPrice32503OutOfStock.urlKey}}" stepKey="seeUrlKey"/> From 2587e3221f56d237588d1fc23dd4aa4e3b076fca Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 10 Dec 2020 15:24:56 +0200 Subject: [PATCH 234/346] updated with OpenEditProductOnBackendActionGroup --- ...tNameToVerifyDataOverridingOnStoreViewLevelTest.xml | 10 +++++----- ...PriceToVerifyDataOverridingOnStoreViewLevelTest.xml | 10 +++++----- .../Test/AdminUpdateSimpleProductTieredPriceTest.xml | 10 +++++----- ...oductWithRegularPriceInStockDisabledProductTest.xml | 10 +++++----- ...leProductWithRegularPriceInStockEnabledFlatTest.xml | 10 +++++----- ...thRegularPriceInStockNotVisibleIndividuallyTest.xml | 10 +++++----- ...WithRegularPriceInStockUnassignFromCategoryTest.xml | 10 +++++----- ...egularPriceInStockVisibleInCatalogAndSearchTest.xml | 10 +++++----- ...WithRegularPriceInStockVisibleInCatalogOnlyTest.xml | 10 +++++----- ...tWithRegularPriceInStockVisibleInSearchOnlyTest.xml | 10 +++++----- ...uctWithRegularPriceInStockWithCustomOptionsTest.xml | 10 +++++----- ...dateSimpleProductWithRegularPriceOutOfStockTest.xml | 10 +++++----- 12 files changed, 60 insertions(+), 60 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductNameToVerifyDataOverridingOnStoreViewLevelTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductNameToVerifyDataOverridingOnStoreViewLevelTest.xml index 5f7cecfde188a..70d6932f6fc17 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductNameToVerifyDataOverridingOnStoreViewLevelTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductNameToVerifyDataOverridingOnStoreViewLevelTest.xml @@ -42,12 +42,12 @@ </after> <!-- Search default simple product in grid --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Assign simple product to created store view --> <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewDropdownToggle}}" stepKey="clickCategoryStoreViewDropdownToggle"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductPriceToVerifyDataOverridingOnStoreViewLevelTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductPriceToVerifyDataOverridingOnStoreViewLevelTest.xml index 8a05ed9d64b8b..f9c90b1190611 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductPriceToVerifyDataOverridingOnStoreViewLevelTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductPriceToVerifyDataOverridingOnStoreViewLevelTest.xml @@ -42,12 +42,12 @@ </after> <!-- Search default simple product in grid --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Assign simple product to created store view --> <click selector="{{AdminCategoryMainActionsSection.CategoryStoreViewDropdownToggle}}" stepKey="clickCategoryStoreViewDropdownToggle"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml index 300b312612253..73ceed8489f7a 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductTieredPriceTest.xml @@ -44,12 +44,12 @@ </after> <!-- Search default simple product in the grid --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with tier price(in stock) --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductTierPrice300InStock.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockDisabledProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockDisabledProductTest.xml index a9630aba467c6..9cae9cc3f1f42 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockDisabledProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockDisabledProductTest.xml @@ -34,12 +34,12 @@ </after> <!-- Search default simple product in the grid page --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price(in stock) --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductDisabled.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml index aa1b1ae702914..4aa1f694a0a24 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatTest.xml @@ -38,12 +38,12 @@ </after> <!-- Search default simple product in the grid page --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductEnabledFlat.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml index 86fac835ce44d..4c4c46c6579c2 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockNotVisibleIndividuallyTest.xml @@ -36,12 +36,12 @@ </after> <!-- Search default simple product in the grid page --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price(in stock) --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductNotVisibleIndividually.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockUnassignFromCategoryTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockUnassignFromCategoryTest.xml index af3861e4e0b64..7bb5f090edf5d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockUnassignFromCategoryTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockUnassignFromCategoryTest.xml @@ -34,12 +34,12 @@ </after> <!--Search default simple product in the grid page --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product by unselecting categories --> <scrollTo selector="{{AdminProductFormSection.productStockStatus}}" stepKey="scroll"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml index 320edba5feeff..36b6711e25c25 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogAndSearchTest.xml @@ -36,12 +36,12 @@ </after> <!-- Search default simple product in the grid page --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price(in stock) --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductRegularPrice245InStock.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml index 77c3e7548a3cf..f3e73845e4a81 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInCatalogOnlyTest.xml @@ -36,12 +36,12 @@ </after> <!-- Search default simple product in the grid --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price(in stock) --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductRegularPrice32501InStock.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml index 39dab0b08915c..5303d489a8235 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockVisibleInSearchOnlyTest.xml @@ -36,12 +36,12 @@ </after> <!-- Search default simple product in the grid --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price(in stock) --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductRegularPrice325InStock.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml index 670030d1d98ea..914e261115cf6 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockWithCustomOptionsTest.xml @@ -36,12 +36,12 @@ </after> <!-- Search default simple product in the grid --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductRegularPriceCustomOptions.name}}" stepKey="fillSimpleProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml index 441bc9b8f8005..bd2d3c239792e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceOutOfStockTest.xml @@ -36,12 +36,12 @@ </after> <!-- Search default simple product in the grid --> - <actionGroup ref="AdminProductCatalogPageOpenActionGroup" stepKey="openProductCatalogPage"/> - <actionGroup ref="FilterProductGridBySku2ActionGroup" stepKey="filterProductGrid"> - <argument name="sku" value="$$initialSimpleProduct.sku$$"/> + <actionGroup ref="AdminClearFiltersActionGroup" stepKey="openProductCatalogPage"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProductGrid"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="clickFirstRowToOpenDefaultSimpleProduct"> + <argument name="product" value="$$initialSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="clickFirstRowToOpenDefaultSimpleProduct"/> - <waitForPageLoad stepKey="waitUntilProductIsOpened"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitUntilProductIsOpened"/> <!-- Update simple product with regular price(out of stock) --> <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{simpleProductRegularPrice32503OutOfStock.name}}" stepKey="fillSimpleProductName"/> From 9c797541a473849301d58f29cb264fff3e850345 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Thu, 10 Dec 2020 07:39:07 -0600 Subject: [PATCH 235/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../Magento/UrlRewrite/Model/UrlRewrite.php | 120 +++++++++--------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index 0f72116ac7614..708811eccd9cc 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -7,17 +7,20 @@ namespace Magento\UrlRewrite\Model; -use Magento\Catalog\Api\CategoryRepositoryInterface; -use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Category; use Magento\Catalog\Model\Product; -use Magento\Cms\Api\PageRepositoryInterface; use Magento\Cms\Model\Page; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\EntityManager\EventManager; use Magento\Framework\Indexer\CacheContext; +use Magento\Framework\Model\AbstractModel; +use Magento\Framework\Model\Context; +use Magento\Framework\Model\ResourceModel\AbstractResource; +use Magento\Framework\Registry; use Magento\Framework\Serialize\Serializer\Json; use Magento\UrlRewrite\Controller\Adminhtml\Url\Rewrite; +use Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollection; /** * UrlRewrite model class @@ -36,32 +39,49 @@ * @method UrlRewrite setStoreId($value) * @method UrlRewrite setDescription($value) */ -class UrlRewrite extends \Magento\Framework\Model\AbstractModel +class UrlRewrite extends AbstractModel { /** * @var Json */ private $serializer; + /** + * @var CacheContext|mixed|null + */ + private $cacheContext; + + /** + * @var EventManager|mixed|null + */ + private $eventManager; + /** * UrlRewrite constructor. * - * @param \Magento\Framework\Model\Context $context - * @param \Magento\Framework\Registry $registry - * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource - * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection + * @param Context $context + * @param Registry $registry + * @param AbstractResource|null $resource + * @param AbstractDb|null $resourceCollection * @param array $data - * @param Json $serializer + * @param Json|null $serializer + * @param CacheContext|null $cacheContext + * @param EventManager|null $eventManager */ public function __construct( - \Magento\Framework\Model\Context $context, - \Magento\Framework\Registry $registry, - \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, - \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, + Context $context, + Registry $registry, + AbstractResource $resource = null, + AbstractDb $resourceCollection = null, array $data = [], - Json $serializer = null - ) { + Json $serializer = null, + CacheContext $cacheContext = null, + EventManager $eventManager = null + ) + { $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->cacheContext = $cacheContext ?: ObjectManager::getInstance()->get(CacheContext::class); + $this->eventManager = $eventManager ?: ObjectManager::getInstance()->get(EventManager::class); parent::__construct($context, $registry, $resource, $resourceCollection, $data); } @@ -72,8 +92,8 @@ public function __construct( */ protected function _construct() { - $this->_init(\Magento\UrlRewrite\Model\ResourceModel\UrlRewrite::class); - $this->_collectionName = \Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollection::class; + $this->_init(ResourceModel\UrlRewrite::class); + $this->_collectionName = UrlRewriteCollection::class; } /** @@ -102,57 +122,37 @@ public function setMetadata($metadata) return $this->setData(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::METADATA, $metadata); } - private function opt1() { - $map = [ - Rewrite::ENTITY_TYPE_PRODUCT => Product::CACHE_TAG, - Rewrite::ENTITY_TYPE_CATEGORY => Category::CACHE_TAG, - Rewrite::ENTITY_TYPE_CMS_PAGE => Page::CACHE_TAG - ]; - - if ($this->getEntityType() !== Rewrite::ENTITY_TYPE_CUSTOM) { - $cacheKey = $map[$this->getEntityType()]; + /** + * Clean cache for the entity which was affected by updating UrlRewrite + * + * @param $entityType + * @param $entityId + */ + private function cleanCacheForEntity($entityType, $entityId) + { + if ($entityType !== Rewrite::ENTITY_TYPE_CUSTOM) { + $map = [ + Rewrite::ENTITY_TYPE_PRODUCT => Product::CACHE_TAG, + Rewrite::ENTITY_TYPE_CATEGORY => Category::CACHE_TAG, + Rewrite::ENTITY_TYPE_CMS_PAGE => Page::CACHE_TAG + ]; - $cacheContext = ObjectManager::getInstance()->get(CacheContext::class); - $eventManager = ObjectManager::getInstance()->get(EventManager::class); + $cacheKey = $map[$entityType]; - $cacheContext->registerEntities($cacheKey, [$this->getEntityId()]); - $eventManager->dispatch('clean_cache_by_tags', ['object' => $cacheContext]); + $this->cacheContext->registerEntities($cacheKey, [$entityId]); + $this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]); } } - private function opt2() { - $map = [ - Rewrite::ENTITY_TYPE_PRODUCT => function ($prodId) { - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = ObjectManager::getInstance()->get(ProductRepositoryInterface::class); - return $productRepository->getById($prodId); - }, - Rewrite::ENTITY_TYPE_CATEGORY => function ($catId) { - /** @var CategoryRepositoryInterface $productRepository */ - $categoryRepository = ObjectManager::getInstance()->get(CategoryRepositoryInterface::class); - return $categoryRepository->get($catId); - }, - Rewrite::ENTITY_TYPE_CMS_PAGE => function ($cmsId) { - /** @var PageRepositoryInterface $productRepository */ - $pageRepository = ObjectManager::getInstance()->get(PageRepositoryInterface::class); - return $pageRepository->getById($cmsId); - }, - Rewrite::ENTITY_TYPE_CUSTOM => false - ]; - - $getter = $map[$this->getEntityType()]; - - if ($getter) { - $entity = $getter($this->getEntityId()); - - $entityManager = ObjectManager::getInstance()->get(EventManager::class); - $entityManager->dispatch('clean_cache_by_tags', ['object' => $entity]); - } + public function afterDelete() + { + $this->cleanCacheForEntity($this->getEntityType(), $this->getEntityId()); + return parent::afterDelete(); // TODO: Change the autogenerated stub } public function afterSave() { - $this->opt1(); - return parent::afterSave(); // TODO: Change the autogenerated stub + $this->cleanCacheForEntity($this->getEntityType(), $this->getEntityId()); + return parent::afterSave(); } } From d30fd1fbed12e593f168629c22f117f58e6dd156 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Thu, 10 Dec 2020 17:20:03 +0200 Subject: [PATCH 236/346] MC-38931: Product URL Rewrites are not removed when product removed from website --- ...uctProcessUrlRewriteSavingObserverTest.php | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php index 64f7acb1feda2..0ceff2aeff5e5 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/ProductProcessUrlRewriteSavingObserverTest.php @@ -14,8 +14,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Event; use Magento\Framework\Event\Observer; -use Magento\Framework\ObjectManagerInterface; -use Magento\Store\Api\StoreWebsiteRelationInterface; +use Magento\Store\Model\StoreResolver\GetStoresListByWebsiteIds; use Magento\UrlRewrite\Model\UrlPersistInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -46,21 +45,11 @@ class ProductProcessUrlRewriteSavingObserverTest extends TestCase */ protected $product; - /** - * @var ObjectManagerInterface - */ - protected $objectManager; - /** * @var ProductProcessUrlRewriteSavingObserver */ protected $model; - /** - * @var StoreWebsiteRelationInterface|MockObject - */ - private $storeRelation; - /** * @var AppendUrlRewritesToProducts|MockObject */ @@ -100,10 +89,6 @@ protected function setUp(): void $this->event->expects($this->any())->method('getProduct')->willReturn($this->product); $this->observer = $this->createPartialMock(Observer::class, ['getEvent']); $this->observer->expects($this->any())->method('getEvent')->willReturn($this->event); - $this->storeRelation = $this->getMockBuilder(StoreWebsiteRelationInterface::class) - ->onlyMethods(['getStoreByWebsiteId']) - ->disableOriginalConstructor() - ->getMock(); $this->scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class) ->onlyMethods(['isSetFlag']) @@ -115,11 +100,16 @@ protected function setUp(): void ->disableOriginalConstructor() ->getMock(); + $getStoresList = $this->getMockBuilder(GetStoresListByWebsiteIds::class) + ->onlyMethods(['execute']) + ->disableOriginalConstructor() + ->getMock(); + $this->model = new ProductProcessUrlRewriteSavingObserver( $this->urlPersist, - $this->storeRelation, $this->appendRewrites, - $this->scopeConfig + $this->scopeConfig, + $getStoresList ); } @@ -228,10 +218,6 @@ public function testExecuteUrlKey( ->method('getIsChangedCategories') ->willReturn($isChangedCategories); - $this->storeRelation->expects($this->any()) - ->method('getStoreByWebsiteId') - ->willReturn([3]); - $this->product->expects($this->any())->method('getWebsiteIds')->will( $this->returnValue($websitesWithProduct) ); From e726f1c75393d38640751a66815618cbe66f9ad8 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Thu, 10 Dec 2020 17:52:33 +0200 Subject: [PATCH 237/346] Add integration test --- .../Magento/TestModuleMview/etc/module.xml | 10 ++++ .../Magento/TestModuleMview/etc/mview.xml | 18 +++++++ .../Magento/TestModuleMview/registration.php | 12 +++++ .../Framework/Mview/View/ChangelogTest.php | 49 +++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 dev/tests/integration/_files/Magento/TestModuleMview/etc/module.xml create mode 100644 dev/tests/integration/_files/Magento/TestModuleMview/etc/mview.xml create mode 100644 dev/tests/integration/_files/Magento/TestModuleMview/registration.php diff --git a/dev/tests/integration/_files/Magento/TestModuleMview/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleMview/etc/module.xml new file mode 100644 index 0000000000000..9808d90ace49c --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMview/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestModuleMview"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMview/etc/mview.xml b/dev/tests/integration/_files/Magento/TestModuleMview/etc/mview.xml new file mode 100644 index 0000000000000..1cabda7a626bf --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMview/etc/mview.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Mview/etc/mview.xsd"> + <view id="test_view_with_additional_columns" class="Magento\Framework\Indexer\Action\Dummy" group="indexer"> + <subscriptions> + <table name="test_mview_table" entity_column="entity_id"> + <additionalColumns> + <column name="additional_column" cl_name="test_additional_column" /> + </additionalColumns> + </table> + </subscriptions> + </view> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMview/registration.php b/dev/tests/integration/_files/Magento/TestModuleMview/registration.php new file mode 100644 index 0000000000000..5c5453c1bd413 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMview/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleMview') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleMview', __DIR__); +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Mview/View/ChangelogTest.php b/dev/tests/integration/testsuite/Magento/Framework/Mview/View/ChangelogTest.php index ba2225fbe5eac..b77807a11da9b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Mview/View/ChangelogTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Mview/View/ChangelogTest.php @@ -6,6 +6,7 @@ namespace Magento\Framework\Mview\View; use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Mview\View; /** * Test Class for \Magento\Framework\Mview\View\Changelog @@ -123,6 +124,54 @@ public function testClear() $this->assertEquals(1, $this->model->getVersion()); //the same that a table is empty } + /** + * Create entity table for MView + * + * @param string $tableName + * @return void + */ + private function createEntityTable(string $tableName) + { + $table = $this->resource->getConnection()->newTable( + $tableName + )->addColumn( + 'entity_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], + 'Version ID' + )->addColumn( + 'additional_column', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['unsigned' => true, 'nullable' => false, 'default' => '0'], + 'Entity ID' + ); + $this->resource->getConnection()->createTable($table); + } + + public function testAdditionalColumns() + { + $tableName = 'test_mview_table'; + $this->createEntityTable($tableName); + $view = $this->objectManager->create(View::class); + $view->load('test_view_with_additional_columns'); + $view->subscribe(); + $this->connection->insert($tableName, ['entity_id' => 12, 'additional_column' => 13]); + $select = $this->connection->select() + ->from($view->getChangelog()->getName(), ['entity_id', 'test_additional_column']); + $actual = $this->connection->fetchAll($select); + $this->assertEquals( + [ + 'entity_id' => "12", + 'test_additional_column' => "13" + ], + reset($actual) + ); + $this->connection->dropTable($tableName); + $this->connection->dropTable($view->getChangelog()->getName()); + } + /** * Test for getList() method * From a4798a0e43c1c8789e14e069baa60a02854d9bd9 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Thu, 10 Dec 2020 14:22:27 -0600 Subject: [PATCH 238/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- app/code/Magento/CatalogUrlRewrite/etc/di.xml | 8 +++++++ app/code/Magento/CmsUrlRewrite/etc/di.xml | 7 ++++++ .../Magento/UrlRewrite/Model/UrlRewrite.php | 22 ++++++++++--------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/etc/di.xml b/app/code/Magento/CatalogUrlRewrite/etc/di.xml index 5fb7d33546d60..62b63d41f0501 100644 --- a/app/code/Magento/CatalogUrlRewrite/etc/di.xml +++ b/app/code/Magento/CatalogUrlRewrite/etc/di.xml @@ -56,6 +56,14 @@ </argument> </arguments> </type> + <type name="Magento\UrlRewrite\Model\UrlRewrite"> + <arguments> + <argument name="entityToCacheTagMap" xsi:type="array"> + <item name="product" xsi:type="const">Magento\Catalog\Model\Product::CACHE_TAG</item> + <item name="category" xsi:type="const">Magento\Catalog\Model\Category::CACHE_TAG</item> + </argument> + </arguments> + </type> <type name="Magento\Eav\Model\Config"> <arguments> <argument name="attributesForPreload" xsi:type="array"> diff --git a/app/code/Magento/CmsUrlRewrite/etc/di.xml b/app/code/Magento/CmsUrlRewrite/etc/di.xml index 497d7a175842d..0463bf5b696c5 100644 --- a/app/code/Magento/CmsUrlRewrite/etc/di.xml +++ b/app/code/Magento/CmsUrlRewrite/etc/di.xml @@ -9,4 +9,11 @@ <type name="Magento\Cms\Model\ResourceModel\Page"> <plugin name="cms_url_rewrite_plugin" type="Magento\CmsUrlRewrite\Plugin\Cms\Model\ResourceModel\Page"/> </type> + <type name="Magento\UrlRewrite\Model\UrlRewrite"> + <arguments> + <argument name="entityToCacheTagMap" xsi:type="array"> + <item name="cms-page" xsi:type="const">Magento\Cms\Model\Page::CACHE_TAG</item> + </argument> + </arguments> + </type> </config> diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index 708811eccd9cc..363a3388daab0 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -56,6 +56,11 @@ class UrlRewrite extends AbstractModel */ private $eventManager; + /** + * @var array + */ + private $entityToCacheTagMap; + /** * UrlRewrite constructor. * @@ -67,6 +72,7 @@ class UrlRewrite extends AbstractModel * @param Json|null $serializer * @param CacheContext|null $cacheContext * @param EventManager|null $eventManager + * @param array $entityToCacheTagMap */ public function __construct( Context $context, @@ -76,12 +82,14 @@ public function __construct( array $data = [], Json $serializer = null, CacheContext $cacheContext = null, - EventManager $eventManager = null + EventManager $eventManager = null, + array $entityToCacheTagMap = [] ) { $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); $this->cacheContext = $cacheContext ?: ObjectManager::getInstance()->get(CacheContext::class); $this->eventManager = $eventManager ?: ObjectManager::getInstance()->get(EventManager::class); + $this->entityToCacheTagMap = $entityToCacheTagMap; parent::__construct($context, $registry, $resource, $resourceCollection, $data); } @@ -130,14 +138,8 @@ public function setMetadata($metadata) */ private function cleanCacheForEntity($entityType, $entityId) { - if ($entityType !== Rewrite::ENTITY_TYPE_CUSTOM) { - $map = [ - Rewrite::ENTITY_TYPE_PRODUCT => Product::CACHE_TAG, - Rewrite::ENTITY_TYPE_CATEGORY => Category::CACHE_TAG, - Rewrite::ENTITY_TYPE_CMS_PAGE => Page::CACHE_TAG - ]; - - $cacheKey = $map[$entityType]; + if ($entityType !== Rewrite::ENTITY_TYPE_CUSTOM && array_key_exists($entityType, $this->entityToCacheTagMap)) { + $cacheKey = $this->entityToCacheTagMap[$entityType]; $this->cacheContext->registerEntities($cacheKey, [$entityId]); $this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]); @@ -147,7 +149,7 @@ private function cleanCacheForEntity($entityType, $entityId) public function afterDelete() { $this->cleanCacheForEntity($this->getEntityType(), $this->getEntityId()); - return parent::afterDelete(); // TODO: Change the autogenerated stub + return parent::afterDelete(); } public function afterSave() From 646cfbfc08dc5fd956a26bbccf286d01babd0e82 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Wed, 9 Dec 2020 16:03:06 -0600 Subject: [PATCH 239/346] MC-39571: [MAGENTO CLOUD] Minimum order value with discount blocking checkout - Fix hidden tax should be taken into account in minimum order amount validation --- .../Model/Checkout/Type/Multishipping.php | 4 +- app/code/Magento/Quote/Model/Quote.php | 8 ++- .../Magento/Quote/Model/Quote/Address.php | 6 ++- .../Magento/Quote/Model/QuoteTest.php | 24 +++++++++ ...rt_rule_with_coupon_5_off_no_condition.php | 49 +++++++++++++++++++ ...ith_coupon_5_off_no_condition_rollback.php | 36 ++++++++++++++ 6 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition.php create mode 100644 dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition_rollback.php diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php index 8845395be406e..8bfff09aa73b2 100644 --- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php +++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php @@ -1185,7 +1185,9 @@ private function validateMinimumAmountForAddressItems() $baseTotal = 0; foreach ($addresses as $address) { - $taxes = $taxInclude ? $address->getBaseTaxAmount() : 0; + $taxes = $taxInclude + ? $address->getBaseTaxAmount() + $address->getBaseDiscountTaxCompensationAmount() + : 0; $baseTotal += $address->getBaseSubtotalWithDiscount() + $taxes; } diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index d2e900138cd06..48cd4b2eb2fad 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -2312,7 +2312,9 @@ public function validateMinimumAmount($multishipping = false) if (!$minOrderMulti) { foreach ($addresses as $address) { - $taxes = ($taxInclude) ? $address->getBaseTaxAmount() : 0; + $taxes = $taxInclude + ? $address->getBaseTaxAmount() + $address->getBaseDiscountTaxCompensationAmount() + : 0; foreach ($address->getQuote()->getItemsCollection() as $item) { /** @var \Magento\Quote\Model\Quote\Item $item */ $amount = $includeDiscount ? @@ -2327,7 +2329,9 @@ public function validateMinimumAmount($multishipping = false) } else { $baseTotal = 0; foreach ($addresses as $address) { - $taxes = ($taxInclude) ? $address->getBaseTaxAmount() : 0; + $taxes = $taxInclude + ? $address->getBaseTaxAmount() + $address->getBaseDiscountTaxCompensationAmount() + : 0; $baseTotal += $includeDiscount ? $address->getBaseSubtotalWithDiscount() + $taxes : $address->getBaseSubtotal() + $taxes; diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php index aee86eb1f8935..7f1ada710ffb7 100644 --- a/app/code/Magento/Quote/Model/Quote/Address.php +++ b/app/code/Magento/Quote/Model/Quote/Address.php @@ -139,7 +139,7 @@ class Address extends AbstractAddress implements const ADDRESS_TYPE_BILLING = 'billing'; const ADDRESS_TYPE_SHIPPING = 'shipping'; - + private const CACHED_ITEMS_ALL = 'cached_items_all'; /** @@ -1217,7 +1217,9 @@ public function validateMinimumAmount() $storeId ); - $taxes = $taxInclude ? $this->getBaseTaxAmount() : 0; + $taxes = $taxInclude + ? $this->getBaseTaxAmount() + $this->getBaseDiscountTaxCompensationAmount() + : 0; return $includeDiscount ? ($this->getBaseSubtotalWithDiscount() + $taxes >= $amount) : diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php index 081cae5f98ee5..94cf6ef108474 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php @@ -737,4 +737,28 @@ private function getCustomerDataArray(): array CustomerInterface::WEBSITE_ID => 1, ]; } + + /** + * @magentoConfigFixture current_store sales/minimum_order/active 1 + * @magentoConfigFixture current_store sales/minimum_order/amount 5 + * @magentoConfigFixture current_store sales/minimum_order/tax_including 1 + * @magentoConfigFixture current_store sales/minimum_order/include_discount_amount 1 + * @magentoConfigFixture current_store tax/calculation/price_includes_tax 1 + * @magentoConfigFixture current_store tax/calculation/apply_after_discount 1 + * @magentoConfigFixture current_store tax/calculation/cross_border_trade_enabled 1 + * @magentoDataFixture Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition.php + * @magentoDataFixture Magento/Tax/_files/tax_rule_region_1_al.php + * @magentoDataFixture Magento/Checkout/_files/quote_with_taxable_product_and_customer.php + */ + public function testValidateMinimumAmountWithPriceInclTaxAndDiscount() + { + /** @var $quote \Magento\Quote\Model\Quote */ + $quote = $this->getQuoteByReservedOrderId->execute('test_order_with_taxable_product'); + $quote->setCouponCode('CART_FIXED_DISCOUNT_5'); + $quote->collectTotals(); + $this->assertEquals(-5, $quote->getShippingAddress()->getBaseDiscountAmount()); + $this->assertEquals(9.3, $quote->getShippingAddress()->getBaseSubtotal()); + $this->assertEquals(5, $quote->getShippingAddress()->getBaseGrandTotal()); + $this->assertTrue($quote->validateMinimumAmount()); + } } diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition.php new file mode 100644 index 0000000000000..6ce2e0789e478 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Model\GroupManagement; +use Magento\Customer\Model\ResourceModel\Group\Collection; +use Magento\SalesRule\Api\CouponRepositoryInterface; +use Magento\SalesRule\Model\Coupon; +use Magento\SalesRule\Model\Rule; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var Collection $groupCollection */ +$groupCollection = $objectManager->get(Collection::class); +$customerGroupIds = $groupCollection->getAllIds(); +/** @var Rule $salesRule */ +$salesRule = $objectManager->create(Rule::class); +$salesRule->setData( + [ + 'name' => 'cart_rule_with_coupon_5_off_no_condition', + 'is_active' => 1, + 'customer_group_ids' => $groupCollection->getAllIds(), + 'coupon_type' => Rule::COUPON_TYPE_SPECIFIC, + 'simple_action' => Rule::CART_FIXED_ACTION, + 'discount_amount' => 5, + 'discount_step' => 0, + 'stop_rules_processing' => 1, + 'website_ids' => [ + $objectManager->get(StoreManagerInterface::class)->getWebsite()->getId(), + ], + 'store_labels' => [ + + 'store_id' => 0, + 'store_label' => 'cart_rule_with_coupon_5_off_no_condition', + ] + ] +); +$objectManager->get(\Magento\SalesRule\Model\ResourceModel\Rule::class)->save($salesRule); + +// Create coupon and assign "5$ fixed discount" rule to this coupon. +$coupon = $objectManager->create(Coupon::class); +$coupon->setRuleId($salesRule->getId()) + ->setCode('CART_FIXED_DISCOUNT_5') + ->setType(0); +$objectManager->get(CouponRepositoryInterface::class)->save($coupon); diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition_rollback.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition_rollback.php new file mode 100644 index 0000000000000..7ecf7a915b1ea --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/cart_rule_with_coupon_5_off_no_condition_rollback.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Registry; +use Magento\SalesRule\Api\RuleRepositoryInterface; +use Magento\SalesRule\Model\Rule; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var SearchCriteriaBuilder $searchCriteriaBuilder */ +$searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class); +$searchCriteria = $searchCriteriaBuilder->addFilter('name', 'cart_rule_with_coupon_5_off_no_condition') + ->create(); +/** @var RuleRepositoryInterface $ruleRepository */ +$ruleRepository = $objectManager->get(RuleRepositoryInterface::class); +$items = $ruleRepository->getList($searchCriteria) + ->getItems(); +/** @var Rule $salesRule */ +$salesRule = array_pop($items); +if ($salesRule !== null) { + $ruleRepository->deleteById($salesRule->getRuleId()); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From 830f4a35214e4fd5c2bb7b04663203a79e85153a Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 11 Dec 2020 11:18:23 +0200 Subject: [PATCH 240/346] MC-24840: Infinite redirect in case of backend URL is different from default website URL --- .../Magento/Backend/App/Area/FrontNameResolver.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Backend/App/Area/FrontNameResolver.php b/app/code/Magento/Backend/App/Area/FrontNameResolver.php index 6f78a3d055299..a927f52b59d95 100644 --- a/app/code/Magento/Backend/App/Area/FrontNameResolver.php +++ b/app/code/Magento/Backend/App/Area/FrontNameResolver.php @@ -120,10 +120,16 @@ public function getFrontName($checkHost = false) */ public function isHostBackend() { - if ($this->config->getValue(self::XML_PATH_USE_CUSTOM_ADMIN_URL)) { - $backendUrl = $this->config->getValue(self::XML_PATH_CUSTOM_ADMIN_URL); + if ($this->scopeConfig->getValue(self::XML_PATH_USE_CUSTOM_ADMIN_URL, ScopeInterface::SCOPE_STORE)) { + $backendUrl = $this->scopeConfig->getValue(self::XML_PATH_CUSTOM_ADMIN_URL, ScopeInterface::SCOPE_STORE); } else { $backendUrl = $this->config->getValue(Store::XML_PATH_UNSECURE_BASE_URL); + if ($backendUrl === null) { + $backendUrl = $this->scopeConfig->getValue( + Store::XML_PATH_UNSECURE_BASE_URL, + ScopeInterface::SCOPE_STORE + ); + } } $host = $this->request->getServer('HTTP_HOST', ''); return stripos($this->getHostWithPort($backendUrl), (string) $host) !== false; From f5cc98e68c00ff0e66d1dcc40b706e3bed1b7c98 Mon Sep 17 00:00:00 2001 From: korovitskyi <o.korovitskyi@atwix.com> Date: Fri, 11 Dec 2020 12:05:16 +0200 Subject: [PATCH 241/346] #31168 fix for customer which have more than two subscriptions --- .../Model/Plugin/CustomerPlugin.php | 21 ------------------- .../Newsletter/etc/extension_attributes.xml | 6 +----- .../Newsletter/Model/Plugin/PluginTest.php | 14 +++++++++++++ 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php index 6bdaa40019f8a..6c42875f5b32d 100644 --- a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php +++ b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php @@ -234,27 +234,6 @@ public function afterGetById(CustomerRepositoryInterface $subject, CustomerInter return $customer; } - /** - * Add subscription status to customer list - * - * @param CustomerRepositoryInterface $subject - * @param SearchResults $searchResults - * @return SearchResults - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function afterGetList(CustomerRepositoryInterface $subject, SearchResults $searchResults): SearchResults - { - foreach ($searchResults->getItems() as $customer) { - /** @var CustomerExtensionInterface $extensionAttributes */ - $extensionAttributes = $customer->getExtensionAttributes(); - - $isSubscribed = (int) $extensionAttributes->getIsSubscribed() === Subscriber::STATUS_SUBSCRIBED ?: false; - $extensionAttributes->setIsSubscribed($isSubscribed); - } - - return $searchResults; - } - /** * Set Is Subscribed extension attribute * diff --git a/app/code/Magento/Newsletter/etc/extension_attributes.xml b/app/code/Magento/Newsletter/etc/extension_attributes.xml index 09925024e97d5..5c38c02c032b0 100644 --- a/app/code/Magento/Newsletter/etc/extension_attributes.xml +++ b/app/code/Magento/Newsletter/etc/extension_attributes.xml @@ -8,10 +8,6 @@ <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd"> <extension_attributes for="Magento\Customer\Api\Data\CustomerInterface"> - <attribute code="is_subscribed" type="boolean" > - <join reference_table="newsletter_subscriber" reference_field="customer_id" join_on_field="entity_id"> - <field>subscriber_status</field> - </join> - </attribute> + <attribute code="is_subscribed" type="boolean"/> </extension_attributes> </config> diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php index 97f59e94d9cfe..133d74aec03da 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php @@ -205,4 +205,18 @@ public function testCustomerWithZeroStoreIdIsSubscribed() $this->assertEquals($customer->getId(), (int)$subscriber->getCustomerId()); $this->assertEquals($currentStore, (int)$subscriber->getStoreId()); } + + /** + * Test get list customer, which have more then 2 subscribes in newsletter_subscriber. + * + * @magentoAppArea frontend + * @magentoDataFixture Magento/Newsletter/_files/subscribers.php + */ + public function testCustomerWithTwoNewsLetterSubscriptions() + { + /** @var \Magento\Framework\Api\SearchCriteriaBuilder $searchBuilder */ + $searchBuilder = Bootstrap::getObjectManager()->create(\Magento\Framework\Api\SearchCriteriaBuilder::class); + $searchCriteria = $searchBuilder->addFilter('entity_id', 1)->create(); + $this->customerRepository->getList($searchCriteria); + } } From 62da7cb6912b4a36845f4e0a8cb2de4dff615202 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Fri, 11 Dec 2020 15:53:28 +0200 Subject: [PATCH 242/346] MC-24840: Infinite redirect in case of backend URL is different from default website URL --- .../App/Area/FrontNameResolverTest.php | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Backend/App/Area/FrontNameResolverTest.php diff --git a/dev/tests/integration/testsuite/Magento/Backend/App/Area/FrontNameResolverTest.php b/dev/tests/integration/testsuite/Magento/Backend/App/Area/FrontNameResolverTest.php new file mode 100644 index 0000000000000..979e8db19efb9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Backend/App/Area/FrontNameResolverTest.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Backend\App\Area; + +use PHPUnit\Framework\TestCase; +use Magento\TestFramework\Helper\Bootstrap; + +/** + * @magentoAppArea adminhtml + */ +class FrontNameResolverTest extends TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var FrontNameResolver + */ + protected $model; + + /** + * @inheritDoc + */ + protected function setUp(): void + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->model = $this->objectManager->create( + FrontNameResolver::class + ); + $_SERVER['HTTP_HOST'] = 'localhost'; + } + + /** + * @magentoDbIsolation enabled + * @magentoConfigFixture current_store web/unsecure/base_url http://example.com/ + */ + public function testIsHostBackend() + { + $this->assertTrue($this->model->isHostBackend()); + } +} From f9445ccaf7fe3300acf451c6950ecee08643f981 Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Fri, 11 Dec 2020 16:05:00 +0200 Subject: [PATCH 243/346] fix stepKey name --- .../AdminApplyTierPriceToProductWithPercentageDiscountTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml index 143fa6657cd3b..0b29d2edb6615 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductWithPercentageDiscountTest.xml @@ -44,7 +44,7 @@ <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="scrollToTopOfPage"/> <actionGroup ref="AdminProductFormOpenAdvancedPricingDialogActionGroup" stepKey="clickOnAdvancedPricingButton"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForCustomerGroupPriceAddButton"/> - <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAndpercente"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="addCustomerGroupAllGroupsQty1PriceDiscountAndpercent"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="fillProductTierPriceQtyInput"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectProductTierPriceValueType"/> From f70063cabec8db464636408f7999d7f48fa9654d Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Fri, 11 Dec 2020 17:27:17 +0200 Subject: [PATCH 244/346] MC-39282: Bundled product cannot be saved when tier price is assigned and Magento\Framework\Api\ExtensibleDataObjectConverter is used to convert product data --- app/code/Magento/Catalog/Model/Product/Type/Price.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Product/Type/Price.php b/app/code/Magento/Catalog/Model/Product/Type/Price.php index 74a6c7f634f81..111e616897d58 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/Price.php +++ b/app/code/Magento/Catalog/Model/Product/Type/Price.php @@ -379,7 +379,7 @@ public function getTierPrices($product) if (array_key_exists('website_price', $price)) { $value = $price['website_price']; } else { - $value = $price['price']; + $value = $price['price'] ?: null; } $tierPrice->setValue($value); $tierPrice->setQty($price['price_qty']); From b58d1f91f7f45024e06f19cd109899a864c7620e Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Fri, 11 Dec 2020 18:06:35 +0200 Subject: [PATCH 245/346] MC-39282: Bundled product cannot be saved when tier price is assigned and Magento\Framework\Api\ExtensibleDataObjectConverter is used to convert product data --- app/code/Magento/Catalog/Model/Product/Type/Price.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Product/Type/Price.php b/app/code/Magento/Catalog/Model/Product/Type/Price.php index 111e616897d58..206f3dba0ee60 100644 --- a/app/code/Magento/Catalog/Model/Product/Type/Price.php +++ b/app/code/Magento/Catalog/Model/Product/Type/Price.php @@ -379,7 +379,7 @@ public function getTierPrices($product) if (array_key_exists('website_price', $price)) { $value = $price['website_price']; } else { - $value = $price['price'] ?: null; + $value = $price['price'] ?? 0; } $tierPrice->setValue($value); $tierPrice->setQty($price['price_qty']); From 11d4a9f35f093f9b7c7eb4ed60a833ab7c841851 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Mon, 14 Dec 2020 10:52:08 +0200 Subject: [PATCH 246/346] MC-39282: Bundled product cannot be saved when tier price is assigned and Magento\Framework\Api\ExtensibleDataObjectConverter is used to convert product data --- .../Unit/Model/Product/Type/PriceTest.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/PriceTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/PriceTest.php index 09ad8bb41de7c..c14bb7f524d03 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/PriceTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/PriceTest.php @@ -263,4 +263,40 @@ function () { ); } } + + /** + * Get tier price with percent value type + * + * @return void + */ + public function testGetPricesWithPercentType(): void + { + $tierPrices = [ + 0 => [ + 'record_id' => 0, + 'cust_group' => 3200, + 'price_qty' => 3, + 'website_id' => 0, + 'value_type' => 'percent', + 'percentage_value' => 10, + ], + ]; + $this->product->setData('tier_price', $tierPrices); + $this->tpFactory->expects($this->any()) + ->method('create') + ->willReturnCallback( + function () { + return $this->objectManagerHelper->getObject(TierPrice::class); + } + ); + $tierPriceExtensionMock = $this->getMockBuilder(ProductTierPriceExtensionInterface::class) + ->onlyMethods(['getPercentageValue', 'setPercentageValue']) + ->getMockForAbstractClass(); + $tierPriceExtensionMock->method('getPercentageValue') + ->willReturn(50); + $this->tierPriceExtensionFactoryMock->method('create') + ->willReturn($tierPriceExtensionMock); + + $this->assertInstanceOf(TierPrice::class, $this->model->getTierPrices($this->product)[0]); + } } From b54e7ae78916d215288b4ddb89d7351b5e183cef Mon Sep 17 00:00:00 2001 From: Vova Yatsyuk <vova.yatsyuk@gmail.com> Date: Mon, 14 Dec 2020 13:35:14 +0200 Subject: [PATCH 247/346] Declare optional argument after required. This prevents PHP fatal error when plugin is added to the one of parent classes. Error example: 'Error: Cannot instantiate interface Magento\Framework\Data\OptionSourceInterface' --- .../MediaGalleryUi/Ui/Component/Listing/Filters/Asset.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/MediaGalleryUi/Ui/Component/Listing/Filters/Asset.php b/app/code/Magento/MediaGalleryUi/Ui/Component/Listing/Filters/Asset.php index f61e34512bfe3..57a59ad800469 100644 --- a/app/code/Magento/MediaGalleryUi/Ui/Component/Listing/Filters/Asset.php +++ b/app/code/Magento/MediaGalleryUi/Ui/Component/Listing/Filters/Asset.php @@ -33,8 +33,8 @@ class Asset extends Select * @param UiComponentFactory $uiComponentFactory * @param FilterBuilder $filterBuilder * @param FilterModifier $filterModifier - * @param OptionSourceInterface $optionsProvider * @param GetContentByAssetIdsInterface $getContentIdentities + * @param OptionSourceInterface $optionsProvider * @param array $components * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -44,8 +44,8 @@ public function __construct( UiComponentFactory $uiComponentFactory, FilterBuilder $filterBuilder, FilterModifier $filterModifier, - OptionSourceInterface $optionsProvider = null, GetContentByAssetIdsInterface $getContentIdentities, + OptionSourceInterface $optionsProvider = null, array $components = [], array $data = [] ) { From b82cae9b4c7c4e356bd19bc8cfc64011612ff702 Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Mon, 14 Dec 2020 15:47:16 +0200 Subject: [PATCH 248/346] MC-39531: guest-carts/{cart_id}/items returns incorrect product name on non-default website --- .../Model/Quote/Plugin/UpdateQuoteStoreId.php | 61 +++++++++++++++++++ app/code/Magento/Quote/etc/webapi_rest/di.xml | 3 + 2 files changed, 64 insertions(+) create mode 100644 app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php diff --git a/app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php b/app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php new file mode 100644 index 0000000000000..4ed347b1eb06d --- /dev/null +++ b/app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Quote\Model\Quote\Plugin; + +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\QuoteRepository; +use Magento\Store\Model\StoreManagerInterface; + +/** + * Updates quote store id. + */ +class UpdateQuoteStoreId +{ + /** + * @var QuoteRepository + */ + private $quoteRepository; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @param QuoteRepository $quoteRepository + * @param StoreManagerInterface $storeManager + */ + public function __construct( + QuoteRepository $quoteRepository, + StoreManagerInterface $storeManager + ) { + $this->quoteRepository = $quoteRepository; + $this->storeManager = $storeManager; + } + + /** + * Update store id in requested quote by store id from request. + * + * @param Quote $subject + * @param null $result + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterLoadByIdWithoutStore( + Quote $subject, + $result + ) { + $quoteStoreId = (int) $subject->getStoreId(); + $storeId = $this->storeManager->getStore() + ->getId() ?: $this->storeManager->getDefaultStoreView() + ->getId(); + if ($storeId !== $quoteStoreId) { + $subject->setStoreId($storeId); + } + } +} diff --git a/app/code/Magento/Quote/etc/webapi_rest/di.xml b/app/code/Magento/Quote/etc/webapi_rest/di.xml index a55d2146be156..6ed9909f04eb9 100644 --- a/app/code/Magento/Quote/etc/webapi_rest/di.xml +++ b/app/code/Magento/Quote/etc/webapi_rest/di.xml @@ -16,4 +16,7 @@ <type name="Magento\Quote\Api\GuestCartItemRepositoryInterface"> <plugin name="updateCartIdFromRequest" type="Magento\Quote\Plugin\UpdateCartId" /> </type> + <type name="Magento\Quote\Model\Quote"> + <plugin name="updateQuoteStoreId" type="Magento\Quote\Model\Quote\Plugin\UpdateQuoteStoreId" /> + </type> </config> From e8d2a5ece6479d6c1b2e3cf17f5245946e34420c Mon Sep 17 00:00:00 2001 From: Viktor Rad <vrad@adobe.com> Date: Mon, 14 Dec 2020 14:13:34 -0600 Subject: [PATCH 249/346] MC-39132: [MAGENTO CLOUD] PWA causing failed Magento Tester results --- .../Magento/Framework/Interception/PluginListGenerator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/Interception/PluginListGenerator.php b/lib/internal/Magento/Framework/Interception/PluginListGenerator.php index effc291bb883b..8f3a03dd4fc20 100644 --- a/lib/internal/Magento/Framework/Interception/PluginListGenerator.php +++ b/lib/internal/Magento/Framework/Interception/PluginListGenerator.php @@ -227,8 +227,6 @@ public function loadScopedVirtualTypes($scopePriorityScheme, $loadedScopes, $plu $data = $this->reader->read($scopeCode) ?: []; unset($data['preferences']); if (count($data) > 0) { - $inherited = []; - $processed = []; $pluginData = $this->merge($data, $pluginData); foreach ($data as $class => $config) { if (isset($config['type'])) { @@ -236,6 +234,8 @@ public function loadScopedVirtualTypes($scopePriorityScheme, $loadedScopes, $plu } } } + $inherited = []; + $processed = []; $loadedScopes[$scopeCode] = true; } if ($this->isCurrentScope($scopeCode)) { From d013abf276cb688657de42d0de6b82abd65cfd45 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Mon, 14 Dec 2020 09:23:59 -0600 Subject: [PATCH 250/346] MC-38913: Associate to Website Functionality - Fix customer associated website should be editable in customer information page --- ...teInCustomerInformationPageActionGroup.xml | 20 +++++++++ .../AdminCustomerGridInlineEditorSection.xml | 3 -- ...minChangeCustomerAssociatedWebsiteTest.xml | 42 ++++++++----------- .../ui_component/customer_listing.xml | 3 ++ .../view/base/web/js/form/element/website.js | 4 -- 5 files changed, 40 insertions(+), 32 deletions(-) create mode 100644 app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminUpdateCustomerWebsiteInCustomerInformationPageActionGroup.xml diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminUpdateCustomerWebsiteInCustomerInformationPageActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminUpdateCustomerWebsiteInCustomerInformationPageActionGroup.xml new file mode 100644 index 0000000000000..bad564c6c9387 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminUpdateCustomerWebsiteInCustomerInformationPageActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminUpdateCustomerWebsiteInCustomerInformationPageActionGroup"> + <annotations> + <description>Update customer website in customer information page</description> + </annotations> + <arguments> + <argument name="websiteName" defaultValue="{{_defaultWebsite.name}}" type="string"/> + </arguments> + <selectOption selector="{{AdminCustomerAccountInformationSection.associateToWebsite}}" userInput="{{websiteName}}" stepKey="changeWebsite"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml index f074217224372..d010844cfffcf 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerGridInlineEditorSection.xml @@ -11,8 +11,5 @@ <section name="AdminCustomerGridInlineEditorSection"> <element name="customerGenderEditor" type="select" selector="tr.data-grid-editable-row:not([style*='display: none']) [name='gender']"/> <element name="saveInGrid" type="button" selector="tr.data-grid-editable-row-actions button.action-primary" timeout="30"/> - <element name="customerEmailEditor" type="select" selector="tr.data-grid-editable-row:not([style*='display: none']) input[name='email']"/> - <element name="customerWebsiteEditor" type="select" selector="tr.data-grid-editable-row:not([style*='display: none']) select[name='website_id']"/> - <element name="cellContent" type="select" selector="//tr[@class='data-grid-editable-row' and not(contains(@style,'display:none'))]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{col}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml index 2f4898921d0b6..469e27129d2c5 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminChangeCustomerAssociatedWebsiteTest.xml @@ -11,15 +11,14 @@ <test name="AdminChangeCustomerAssociatedWebsiteTest"> <annotations> <features value="Customer"/> - <title value="Admin should not be able to change customer assigned website ID"/> - <description value="Admin should not be able to change customer assigned website ID"/> + <title value="Admin should be able to change customer associated website ID"/> + <description value="Admin should be able to change customer associated website ID"/> <severity value="AVERAGE"/> <useCaseId value="MC-38913"/> <testCaseId value="MC-39764"/> <stories value="Customer Edit"/> <group value="customer"/> </annotations> - <before> <!--Login to admin--> <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> @@ -45,9 +44,6 @@ <after> <!--Delete customer--> <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> - <!--Reset customer grid filter--> - <actionGroup ref="AdminOpenCustomersGridActionGroup" stepKey="navigateToCustomersPage"/> - <actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearCustomersGridFilter"/> <!--Delete custom website--> <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteWebsite"> <argument name="websiteName" value="{{NewWebSiteData.name}}"/> @@ -55,31 +51,27 @@ <!--Logout from admin--> <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> </after> - <!--Open customer grid--> - <actionGroup ref="AdminOpenCustomersGridActionGroup" stepKey="navigateToCustomersPage"/> - <!--Filter customers grid by email--> - <actionGroup ref="AdminFilterCustomerGridByEmail" stepKey="filterCustomer"> - <argument name="email" value="$createCustomer.email$"/> - </actionGroup> - <!--Click on customer row to open inline editor--> - <click selector="{{AdminDataGridTableSection.rowTemplate($createCustomer.email$)}}" stepKey="clickCustomersGridRow"/> - <!--Wait for inline editor to open--> - <waitForElementVisible selector="{{AdminCustomerGridInlineEditorSection.customerEmailEditor}}" stepKey="waitForEditor"/> - <!--Assert that website is not editable--> - <dontSeeElement selector="{{AdminCustomerGridInlineEditorSection.customerWebsiteEditor}}" stepKey="dontSeeWebsiteEditor"/> - <!--Assert that "Main Website" is displayed in website cell--> - <see selector="{{AdminCustomerGridInlineEditorSection.cellContent('Web Site')}}" userInput="{{_defaultWebsite.name}}" stepKey="assertThatMainWebsiteIsDisplayedInWebsiteCell"/> <!--Open customer edit page--> <actionGroup ref="AdminOpenCustomerEditPageActionGroup" stepKey="openCustomerEditPage"> <argument name="customerId" value="$createCustomer.id$"/> </actionGroup> <!--Navigate to "Account Information" tab--> <actionGroup ref="AdminOpenAccountInformationTabFromCustomerEditPageActionGroup" stepKey="openAccountInformationEditPage"/> - <!--Assert that "Main Website" is selected in website selector--> + <!--Verify that "Main Website" is selected in website selector--> <seeOptionIsSelected selector="{{AdminCustomerAccountInformationSection.associateToWebsite}}" userInput="{{_defaultWebsite.name}}" stepKey="assertThatMainWebsiteIsSelected"/> - <!--Assert that website selector is disabled--> - <assertElementContainsAttribute stepKey="assertThatWebsiteSelectorIsDisabled"> - <expectedResult selector="{{AdminCustomerAccountInformationSection.associateToWebsite}}" attribute="disabled" type="string"/> - </assertElementContainsAttribute> + <!--Change customer website to "Second Website"--> + <actionGroup ref="AdminUpdateCustomerWebsiteInCustomerInformationPageActionGroup" stepKey="updateCustomerWebsite"> + <argument name="websiteName" value="{{NewWebSiteData.name}}"/> + </actionGroup> + <!--Verify that changes are saved successfully--> + <actionGroup ref="AdminSaveCustomerAndAssertSuccessMessage" stepKey="assertThatChangesAreSavedSuccessfully"/> + <!--Open customer edit page--> + <actionGroup ref="AdminOpenCustomerEditPageActionGroup" stepKey="openCustomerEditPage2"> + <argument name="customerId" value="$createCustomer.id$"/> + </actionGroup> + <!--Navigate to "Account Information" tab--> + <actionGroup ref="AdminOpenAccountInformationTabFromCustomerEditPageActionGroup" stepKey="openAccountInformationEditPage2"/> + <!--Verify that "Second Website" is selected in website selector--> + <seeOptionIsSelected selector="{{AdminCustomerAccountInformationSection.associateToWebsite}}" userInput="{{NewWebSiteData.name}}" stepKey="assertThatSecondWebsiteIsSelected"/> </test> </tests> diff --git a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml index b60506ab856c4..97ae9a9953eb6 100644 --- a/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml +++ b/app/code/Magento/Customer/view/adminhtml/ui_component/customer_listing.xml @@ -190,6 +190,9 @@ <column name="website_id" class="Magento\Customer\Ui\Component\Listing\Column\Websites" component="Magento_Ui/js/grid/columns/select" sortOrder="110"> <settings> <filter>select</filter> + <editor> + <editorType>select</editorType> + </editor> <dataType>select</dataType> <label translate="true">Web Site</label> </settings> diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/website.js b/app/code/Magento/Ui/view/base/web/js/form/element/website.js index 3c99cc0874cf9..0d1ed2d9961a1 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/website.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/website.js @@ -26,10 +26,6 @@ define([ initialize: function () { this._super(); - if (this.customerId || this.isGlobalScope) { - this.disable(true); - } - return this; } }); From 66c3bff0b4c5aff1cfd1dd26bd7719bd622d8862 Mon Sep 17 00:00:00 2001 From: korovitskyi <o.korovitskyi@atwix.com> Date: Tue, 15 Dec 2020 00:04:52 +0200 Subject: [PATCH 251/346] #31168 updated after get list method --- .../Model/Plugin/CustomerPlugin.php | 31 +++++++++++++++++++ .../Newsletter/Model/Plugin/PluginTest.php | 6 +++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php index 6c42875f5b32d..d3f8bcb8765c3 100644 --- a/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php +++ b/app/code/Magento/Newsletter/Model/Plugin/CustomerPlugin.php @@ -234,6 +234,37 @@ public function afterGetById(CustomerRepositoryInterface $subject, CustomerInter return $customer; } + /** + * Add subscription status to customer list + * + * @param CustomerRepositoryInterface $subject + * @param SearchResults $searchResults + * @return SearchResults + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetList(CustomerRepositoryInterface $subject, SearchResults $searchResults): SearchResults + { + $customerEmails = []; + + foreach ($searchResults->getItems() as $customer) { + $customerEmails[] = $customer->getEmail(); + } + + $collection = $this->collectionFactory->create(); + $collection->addFieldToFilter('subscriber_email', ['in' => $customerEmails]); + + foreach ($searchResults->getItems() as $customer) { + /** @var CustomerExtensionInterface $extensionAttributes */ + $extensionAttributes = $customer->getExtensionAttributes(); + /** @var Subscriber $subscribe */ + $subscribe = $collection->getItemByColumnValue('subscriber_email', $customer->getEmail()); + $isSubscribed = $subscribe && (int) $subscribe->getStatus() === Subscriber::STATUS_SUBSCRIBED; + $extensionAttributes->setIsSubscribed($isSubscribed); + } + + return $searchResults; + } + /** * Set Is Subscribed extension attribute * diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php index 133d74aec03da..719d78b07ca3c 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Model/Plugin/PluginTest.php @@ -217,6 +217,10 @@ public function testCustomerWithTwoNewsLetterSubscriptions() /** @var \Magento\Framework\Api\SearchCriteriaBuilder $searchBuilder */ $searchBuilder = Bootstrap::getObjectManager()->create(\Magento\Framework\Api\SearchCriteriaBuilder::class); $searchCriteria = $searchBuilder->addFilter('entity_id', 1)->create(); - $this->customerRepository->getList($searchCriteria); + $items = $this->customerRepository->getList($searchCriteria)->getItems(); + /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ + $customer = $items[0]; + $extensionAttributes = $customer->getExtensionAttributes(); + $this->assertTrue($extensionAttributes->getIsSubscribed()); } } From 93c78c070d17c5363c6ce5890d54e39fcdffebc0 Mon Sep 17 00:00:00 2001 From: Viktor Rad <vrad@adobe.com> Date: Mon, 14 Dec 2020 16:08:00 -0600 Subject: [PATCH 252/346] MC-39132: [MAGENTO CLOUD] PWA causing failed Magento Tester results --- .../Interception/PluginListGeneratorTest.php | 61 ++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Interception/PluginListGeneratorTest.php b/dev/tests/integration/testsuite/Magento/Framework/Interception/PluginListGeneratorTest.php index 1046c678e253a..bda4cdd6cbaa5 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Interception/PluginListGeneratorTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Interception/PluginListGeneratorTest.php @@ -23,7 +23,14 @@ class PluginListGeneratorTest extends TestCase /** * Generated plugin list config for frontend scope */ - const CACHE_ID = 'primary|global|frontend|plugin-list'; + const CACHE_ID_FRONTEND = 'primary|global|frontend|plugin-list'; + + /** + * Generated plugin list config for dummy scope + */ + const CACHE_ID_DUMMY = 'primary|global|dummy|plugin-list'; + + private $cacheIds = [self::CACHE_ID_FRONTEND, self::CACHE_ID_DUMMY]; /** * @var PluginListGenerator @@ -90,31 +97,51 @@ protected function setUp(): void */ public function testPluginListConfigGeneration() { - $scopes = ['frontend']; + $scopes = ['global', 'frontend', 'dummy']; + $globalPlugin = 'genericHeaderPlugin'; + $frontendPlugin = 'response-http-page-cache'; $this->model->write($scopes); - $configData = $this->model->load(self::CACHE_ID); - $this->assertNotEmpty($configData[0]); - $this->assertNotEmpty($configData[1]); - $this->assertNotEmpty($configData[2]); - $expected = [ + $configDataFrontend = $this->model->load(self::CACHE_ID_FRONTEND); + $this->assertNotEmpty($configDataFrontend[0]); + $this->assertNotEmpty($configDataFrontend[1]); + $this->assertNotEmpty($configDataFrontend[2]); + $expectedFrontend = [ 1 => [ - 0 => 'genericHeaderPlugin', - 1 => 'response-http-page-cache' + 0 => $globalPlugin, + 1 => $frontendPlugin ] ]; // Here in test is assumed that this class below has 3 plugins. But the amount of plugins and class itself // may vary. If it is changed, please update these assertions. $this->assertArrayHasKey( 'Magento\\Framework\\App\\Response\\Http_sendResponse___self', - $configData[2], + $configDataFrontend[2], 'Processed plugin does not exist in the processed plugins array.' ); $this->assertSame( - $expected, - $configData[2]['Magento\\Framework\\App\\Response\\Http_sendResponse___self'], + $expectedFrontend, + $configDataFrontend[2]['Magento\\Framework\\App\\Response\\Http_sendResponse___self'], 'Plugin configurations are not equal' ); + + $configDataDummy = $this->model->load(self::CACHE_ID_DUMMY); + /** + * Make sure "dummy" scope with no plugins in system should not contain plugins from "frontend" scope + */ + $this->assertNotContains( + $frontendPlugin, + $configDataDummy[2]['Magento\\Framework\\App\\Response\\Http_sendResponse___self'][1], + 'Plugin configurations are not equal. "dummy" scope should not contain plugins from "frontend" scope' + ); + /** + * Make sure "dummy" scope with no plugins in system should contain plugins from "global" scope + */ + $this->assertContains( + $globalPlugin, + $configDataDummy[2]['Magento\\Framework\\App\\Response\\Http_sendResponse___self'][1], + 'Plugin configurations are not equal. "dummy" scope should contain plugins from "global" scope' + ); } /** @@ -137,11 +164,13 @@ private function getCustomDirs(): array */ protected function tearDown(): void { - $filePath = $this->directoryList->getPath(DirectoryList::GENERATED_METADATA) - . '/' . self::CACHE_ID . '.' . 'php'; + foreach ($this->cacheIds as $cacheId) { + $filePath = $this->directoryList->getPath(DirectoryList::GENERATED_METADATA) + . '/' . $cacheId . '.' . 'php'; - if (file_exists($filePath)) { - $this->file->deleteFile($filePath); + if (file_exists($filePath)) { + $this->file->deleteFile($filePath); + } } } } From bc231ce31a22b9f8120d1a9542a066cbc61ba70a Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Tue, 15 Dec 2020 09:56:53 +0200 Subject: [PATCH 253/346] updated testCaseId --- .../Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml index a4f4e006837e1..794d09226d87f 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminMassOrdersCancelClosedAndCompleteTest.xml @@ -14,7 +14,7 @@ <title value="Mass cancel orders in status Complete, Closed"/> <description value="Try to cancel orders in status Complete, Closed"/> <severity value="MAJOR"/> - <testCaseId value="MC-16183"/> + <testCaseId value="MC-39905"/> <group value="sales"/> <group value="mtf_migrated"/> </annotations> From cbc884d700a4e7178bb575e4f6ecfed349428f33 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 15 Dec 2020 10:39:06 +0200 Subject: [PATCH 254/346] added AdminSelectAttributeSetActionGroup --- .../AdminSelectAttributeSetActionGroup.xml | 24 +++++++++++++++++++ .../AdminChangeProductAttributeSetTest.xml | 6 ++--- ...ateProductAttributesStoreViewScopeTest.xml | 4 +++- ...AdminConfigurableProductBulkUpdateTest.xml | 7 ++++-- 4 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetActionGroup.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetActionGroup.xml new file mode 100644 index 0000000000000..b0d0cc75b0e74 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminSelectAttributeSetActionGroup"> + <annotations> + <description></description> + </annotations> + <arguments> + <argument name="attributeSet" type="entity"/> + </arguments> + + <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> + <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSet.attribute_set_name}}" stepKey="searchForAttrSet"/> + <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml index 3b8c2cb736721..89b39cdd93355 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml @@ -60,9 +60,9 @@ <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="$$createAttributeSet.attribute_set_name$$" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="CatalogAttributeSet"/> + </actionGroup> <waitForText userInput="$$createProductAttribute.default_frontend_label$$" stepKey="seeAttributeInForm"/> </test> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml index 30ab17f65f3c8..0312d7279d214 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml @@ -52,7 +52,9 @@ <!-- Update attribute --> <click selector="{{AdminEditProductAttributesSection.ChangeAttributeDescriptionToggle}}" stepKey="toggleToChangeDescription"/> <fillField selector="{{AdminEditProductAttributesSection.AttributeDescription}}" userInput="Updated $$createProductOne.custom_attributes[description]$$" stepKey="fillAttributeDescriptionField"/> - <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="save"/> + <actionGroup ref="AdminSaveProductsMassAttributesUpdateActionGroup" stepKey="save"/> + <!-- <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForSuccessMessage"/> --> + <!-- <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="save"/> --> <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="Message is added to queue" stepKey="seeAttributeUpateSuccessMsg"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml index 556ede0bdc06f..d4875684b70c1 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml @@ -59,8 +59,11 @@ <!-- Update the description --> <click selector="{{AdminUpdateAttributesSection.toggleDescription}}" stepKey="clickToggleDescription"/> <fillField selector="{{AdminUpdateAttributesSection.description}}" userInput="MFTF automation!" stepKey="fillDescription"/> - <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="clickSave"/> - <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" time="60" stepKey="waitForSuccessMessage"/> + <actionGroup ref="AdminSaveProductsMassAttributesUpdateActionGroup" stepKey="clickSave"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForSuccessMessage"/> + + <!-- <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="clickSave"/> + <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" time="60" stepKey="waitForSuccessMessage"/> --> <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="Message is added to queue" stepKey="seeAttributeUpdateSuccessMsg"/> <!-- Apply changes --> From 7f127923ba83be5dba9caef78ce6f584e0ec16e9 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Tue, 15 Dec 2020 11:48:12 +0200 Subject: [PATCH 255/346] MC-39104: 2 error messages in Cart when product is out of stock --- .../Model/Quote/Item/QuantityValidator.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php index 317a573a653e9..b4754eea5c064 100644 --- a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php +++ b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php @@ -157,11 +157,13 @@ public function validate(Observer $observer) if ($stockStatus->getStockStatus() === Stock::STOCK_OUT_OF_STOCK || $parentStockStatus && $parentStockStatus->getStockStatus() == Stock::STOCK_OUT_OF_STOCK ) { - $quoteItem->addErrorInfo( - 'cataloginventory', - Data::ERROR_QTY, - __('This product is out of stock.') - ); + if (!$quoteItem->getStockStateResult() && !$quoteItem->getStockStateResult()->getHasError()) { + $quoteItem->addErrorInfo( + 'cataloginventory', + Data::ERROR_QTY, + __('This product is out of stock.') + ); + } $quoteItem->getQuote()->addErrorInfo( 'stock', 'cataloginventory', From 55b0fc25c1a643a25a5af2e034f956efbddfff84 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 15 Dec 2020 12:18:24 +0200 Subject: [PATCH 256/346] updated tests with new ActionGroup --- .../Test/AdminAttributeSetSelectionTest.xml | 18 ++++++++++++------ .../AdminBasicBundleProductAttributesTest.xml | 8 +++++--- ...tributeSetOnEditProductPageActionGroup.xml} | 11 +++++------ .../AdminChangeProductAttributeSetTest.xml | 4 ++-- .../Test/AdminCreateAttributeSetEntityTest.xml | 8 +++++--- ...dminCreateProductCustomAttributeSetTest.xml | 8 +++++--- 6 files changed, 34 insertions(+), 23 deletions(-) rename app/code/Magento/Catalog/Test/Mftf/ActionGroup/{AdminSelectAttributeSetActionGroup.xml => AdminSelectAttributeSetOnEditProductPageActionGroup.xml} (69%) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml index ca8a35ee7a363..ceed14e76fb4b 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml @@ -42,9 +42,13 @@ <!-- Switch from default attribute set to new attribute set --> <amOnPage url="{{AdminProductCreatePage.url('4', 'bundle')}}" stepKey="goToNewProductPage"/> <waitForPageLoad stepKey="wait2"/> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> + <fillField selector="{{AdminProductFormBundleSection.productName}}" userInput="{{BundleProduct.name}}" stepKey="fillProductName"/> <fillField selector="{{AdminProductFormBundleSection.productSku}}" userInput="{{BundleProduct.sku}}" stepKey="fillProductSku"/> @@ -64,9 +68,11 @@ <click selector="{{AdminProductFiltersSection.attributeSetOfFirstRow(ProductAttributeFrontendLabel.label)}}" stepKey="clickAttributeSet2"/> <waitForPageLoad stepKey="waitForPageLoad2"/> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet2"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{BundleProduct.defaultAttribute}}" stepKey="searchForAttrSet2"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet2"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet2"> + <argument name="attributeSet" value="{{BundleProduct.defaultAttribute}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet2"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet2"/> <!--save the product/published by default--> <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="clickSaveButton2"/> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml index 79d85c6ced957..228c1d3cf1def 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml @@ -109,9 +109,11 @@ <checkOption selector="{{AdminProductFormBundleSection.enableDisableToggle}}" stepKey="clickOnEnableDisableToggleAgain"/> <!--Apply Attribute Set--> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{ProductAttributeFrontendLabelTwo.label}}" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResultByName(ProductAttributeFrontendLabelTwo.label)}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="{{ProductAttributeFrontendLabelTwo.label}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <!--Product name and SKU--> <fillField selector="{{AdminProductFormBundleSection.productName}}" userInput="{{BundleProduct.name2}}" stepKey="fillProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml similarity index 69% rename from app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetActionGroup.xml rename to app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml index b0d0cc75b0e74..2307ad313ad3c 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml @@ -8,17 +8,16 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="AdminSelectAttributeSetActionGroup"> + <actionGroup name="AdminSelectAttributeSetOnEditProductPageActionGroup"> <annotations> <description></description> </annotations> <arguments> - <argument name="attributeSet" type="entity"/> + <argument name="attributeSet" type="string"/> </arguments> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSet.attribute_set_name}}" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> - + <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="clickAttributeSetDropdown"/> + <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSet}}" stepKey="searchForAttributeSet"/> + <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttributeSet"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml index 89b39cdd93355..7c124a60c7877 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml @@ -60,8 +60,8 @@ <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> - <actionGroup ref="AdminSelectAttributeSetActionGroup" stepKey="startEditAttrSet"> - <argument name="attributeSet" value="CatalogAttributeSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="$$createAttributeSet.attribute_set_name$$"/> </actionGroup> <waitForText userInput="$$createProductAttribute.default_frontend_label$$" stepKey="seeAttributeInForm"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml index 9fef5e4203167..8d3fbbaa34355 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml @@ -64,9 +64,11 @@ </actionGroup> <!-- Switch from default attribute set to new attribute set --> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="$$createAttributeSet.attribute_set_name$$" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="$$createAttributeSet.attribute_set_name$$"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <!-- See new attribute set --> <see selector="{{AdminProductFormSection.attributeSet}}" userInput="$$createAttributeSet.attribute_set_name$$" stepKey="seeAttributeSetName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml index d2278f3ddae1d..d1110f593545d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml @@ -62,9 +62,11 @@ <!-- Switch from default attribute set to new attribute set --> <!-- A scrollToTopOfPage is needed to hide the floating header --> <scrollToTopOfPage stepKey="scrollToTop"/> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <!-- See new attibute set --> <seeElementInDOM selector="{{AdminProductFormSection.divByDataIndex('testgroupname')}}" stepKey="seeTestGroupName"/> From 88b58a08d39906584398e0c7762413e18c054a27 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 15 Dec 2020 12:25:08 +0200 Subject: [PATCH 257/346] refactored --- ...AdminSelectAttributeSetOnEditProductPageActionGroup.xml | 3 ++- .../Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml | 2 ++ .../AdminMassUpdateProductAttributesStoreViewScopeTest.xml | 4 +--- .../AdminConfigurableProductBulkUpdateTest.xml | 7 ++----- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml index 2307ad313ad3c..42f7f72c1cd73 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml @@ -10,7 +10,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminSelectAttributeSetOnEditProductPageActionGroup"> <annotations> - <description></description> + <description>Selects the specified value from the Attribute Set dropdown. + The Edit Product Page should be opened prior to Action Group execution</description> </annotations> <arguments> <argument name="attributeSet" type="string"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml index 7c124a60c7877..e7d4241500bfb 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml @@ -63,6 +63,8 @@ <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> <argument name="attributeSet" value="$$createAttributeSet.attribute_set_name$$"/> </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <waitForText userInput="$$createProductAttribute.default_frontend_label$$" stepKey="seeAttributeInForm"/> </test> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml index 0312d7279d214..30ab17f65f3c8 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassUpdateProductAttributesStoreViewScopeTest/AdminMassUpdateProductAttributesStoreViewScopeTest.xml @@ -52,9 +52,7 @@ <!-- Update attribute --> <click selector="{{AdminEditProductAttributesSection.ChangeAttributeDescriptionToggle}}" stepKey="toggleToChangeDescription"/> <fillField selector="{{AdminEditProductAttributesSection.AttributeDescription}}" userInput="Updated $$createProductOne.custom_attributes[description]$$" stepKey="fillAttributeDescriptionField"/> - <actionGroup ref="AdminSaveProductsMassAttributesUpdateActionGroup" stepKey="save"/> - <!-- <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForSuccessMessage"/> --> - <!-- <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="save"/> --> + <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="save"/> <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="Message is added to queue" stepKey="seeAttributeUpateSuccessMsg"/> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml index d4875684b70c1..556ede0bdc06f 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/AdminConfigurableProductUpdateTest/AdminConfigurableProductBulkUpdateTest.xml @@ -59,11 +59,8 @@ <!-- Update the description --> <click selector="{{AdminUpdateAttributesSection.toggleDescription}}" stepKey="clickToggleDescription"/> <fillField selector="{{AdminUpdateAttributesSection.description}}" userInput="MFTF automation!" stepKey="fillDescription"/> - <actionGroup ref="AdminSaveProductsMassAttributesUpdateActionGroup" stepKey="clickSave"/> - <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForSuccessMessage"/> - - <!-- <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="clickSave"/> - <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" time="60" stepKey="waitForSuccessMessage"/> --> + <click selector="{{AdminEditProductAttributesSection.Save}}" stepKey="clickSave"/> + <waitForElementVisible selector="{{AdminProductMessagesSection.successMessage}}" time="60" stepKey="waitForSuccessMessage"/> <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="Message is added to queue" stepKey="seeAttributeUpdateSuccessMsg"/> <!-- Apply changes --> From 9d505f4662e54e77b43c392ee57976722bfb3853 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Tue, 15 Dec 2020 12:27:17 +0200 Subject: [PATCH 258/346] added AdminSelectAttributeSetOnEditProductPageActionGroup --- .../Test/AdminAttributeSetSelectionTest.xml | 18 +++++++++----- .../AdminBasicBundleProductAttributesTest.xml | 8 ++++--- ...tributeSetOnEditProductPageActionGroup.xml | 24 +++++++++++++++++++ .../AdminChangeProductAttributeSetTest.xml | 8 ++++--- .../AdminCreateAttributeSetEntityTest.xml | 8 ++++--- ...minCreateProductCustomAttributeSetTest.xml | 8 ++++--- 6 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml index ca8a35ee7a363..ceed14e76fb4b 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminAttributeSetSelectionTest.xml @@ -42,9 +42,13 @@ <!-- Switch from default attribute set to new attribute set --> <amOnPage url="{{AdminProductCreatePage.url('4', 'bundle')}}" stepKey="goToNewProductPage"/> <waitForPageLoad stepKey="wait2"/> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> + <fillField selector="{{AdminProductFormBundleSection.productName}}" userInput="{{BundleProduct.name}}" stepKey="fillProductName"/> <fillField selector="{{AdminProductFormBundleSection.productSku}}" userInput="{{BundleProduct.sku}}" stepKey="fillProductSku"/> @@ -64,9 +68,11 @@ <click selector="{{AdminProductFiltersSection.attributeSetOfFirstRow(ProductAttributeFrontendLabel.label)}}" stepKey="clickAttributeSet2"/> <waitForPageLoad stepKey="waitForPageLoad2"/> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet2"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{BundleProduct.defaultAttribute}}" stepKey="searchForAttrSet2"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet2"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet2"> + <argument name="attributeSet" value="{{BundleProduct.defaultAttribute}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet2"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet2"/> <!--save the product/published by default--> <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="clickSaveButton2"/> diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml index 79d85c6ced957..228c1d3cf1def 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/AdminBasicBundleProductAttributesTest.xml @@ -109,9 +109,11 @@ <checkOption selector="{{AdminProductFormBundleSection.enableDisableToggle}}" stepKey="clickOnEnableDisableToggleAgain"/> <!--Apply Attribute Set--> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{ProductAttributeFrontendLabelTwo.label}}" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResultByName(ProductAttributeFrontendLabelTwo.label)}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="{{ProductAttributeFrontendLabelTwo.label}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <!--Product name and SKU--> <fillField selector="{{AdminProductFormBundleSection.productName}}" userInput="{{BundleProduct.name2}}" stepKey="fillProductName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml new file mode 100644 index 0000000000000..42f7f72c1cd73 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminSelectAttributeSetOnEditProductPageActionGroup"> + <annotations> + <description>Selects the specified value from the Attribute Set dropdown. + The Edit Product Page should be opened prior to Action Group execution</description> + </annotations> + <arguments> + <argument name="attributeSet" type="string"/> + </arguments> + + <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="clickAttributeSetDropdown"/> + <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSet}}" stepKey="searchForAttributeSet"/> + <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttributeSet"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml index 3b8c2cb736721..e7d4241500bfb 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminChangeProductAttributeSetTest.xml @@ -60,9 +60,11 @@ <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="$$createAttributeSet.attribute_set_name$$" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="$$createAttributeSet.attribute_set_name$$"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <waitForText userInput="$$createProductAttribute.default_frontend_label$$" stepKey="seeAttributeInForm"/> </test> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml index 9fef5e4203167..8d3fbbaa34355 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateAttributeSetEntityTest.xml @@ -64,9 +64,11 @@ </actionGroup> <!-- Switch from default attribute set to new attribute set --> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="$$createAttributeSet.attribute_set_name$$" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="$$createAttributeSet.attribute_set_name$$"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <!-- See new attribute set --> <see selector="{{AdminProductFormSection.attributeSet}}" userInput="$$createAttributeSet.attribute_set_name$$" stepKey="seeAttributeSetName"/> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml index d2278f3ddae1d..d1110f593545d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCreateProductCustomAttributeSetTest.xml @@ -62,9 +62,11 @@ <!-- Switch from default attribute set to new attribute set --> <!-- A scrollToTopOfPage is needed to hide the floating header --> <scrollToTopOfPage stepKey="scrollToTop"/> - <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> - <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{ProductAttributeFrontendLabel.label}}" stepKey="searchForAttrSet"/> - <click selector="{{AdminProductFormSection.attributeSetFilterResult}}" stepKey="selectAttrSet"/> + <actionGroup ref="AdminSelectAttributeSetOnEditProductPageActionGroup" stepKey="startEditAttrSet"> + <argument name="attributeSet" value="{{ProductAttributeFrontendLabel.label}}"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="searchForAttrSet"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="selectAttrSet"/> <!-- See new attibute set --> <seeElementInDOM selector="{{AdminProductFormSection.divByDataIndex('testgroupname')}}" stepKey="seeTestGroupName"/> From 8752d9ccbc1a5786078bacb23507213b454a5634 Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Tue, 15 Dec 2020 14:20:55 +0200 Subject: [PATCH 259/346] MC-39531: guest-carts/{cart_id}/items returns incorrect product name on non-default website --- .../Model/Quote/Plugin/UpdateQuoteStoreId.php | 26 ++-- app/code/Magento/Quote/etc/webapi_soap/di.xml | 3 + .../Quote/Api/GuestCartItemRepositoryTest.php | 113 ++++++++++++++---- 3 files changed, 97 insertions(+), 45 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php b/app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php index 4ed347b1eb06d..bffa0084e35bd 100644 --- a/app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php +++ b/app/code/Magento/Quote/Model/Quote/Plugin/UpdateQuoteStoreId.php @@ -8,7 +8,6 @@ namespace Magento\Quote\Model\Quote\Plugin; use Magento\Quote\Model\Quote; -use Magento\Quote\Model\QuoteRepository; use Magento\Store\Model\StoreManagerInterface; /** @@ -16,25 +15,17 @@ */ class UpdateQuoteStoreId { - /** - * @var QuoteRepository - */ - private $quoteRepository; - /** * @var StoreManagerInterface */ private $storeManager; /** - * @param QuoteRepository $quoteRepository * @param StoreManagerInterface $storeManager */ public function __construct( - QuoteRepository $quoteRepository, StoreManagerInterface $storeManager ) { - $this->quoteRepository = $quoteRepository; $this->storeManager = $storeManager; } @@ -42,20 +33,17 @@ public function __construct( * Update store id in requested quote by store id from request. * * @param Quote $subject - * @param null $result - * @return void + * @param Quote $result + * @return Quote * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function afterLoadByIdWithoutStore( - Quote $subject, - $result - ) { - $quoteStoreId = (int) $subject->getStoreId(); + public function afterLoadByIdWithoutStore(Quote $subject, Quote $result): Quote + { $storeId = $this->storeManager->getStore() ->getId() ?: $this->storeManager->getDefaultStoreView() ->getId(); - if ($storeId !== $quoteStoreId) { - $subject->setStoreId($storeId); - } + $result->setStoreId($storeId); + + return $result; } } diff --git a/app/code/Magento/Quote/etc/webapi_soap/di.xml b/app/code/Magento/Quote/etc/webapi_soap/di.xml index 27d5ff7753425..4b7646b6e1ef3 100644 --- a/app/code/Magento/Quote/etc/webapi_soap/di.xml +++ b/app/code/Magento/Quote/etc/webapi_soap/di.xml @@ -13,4 +13,7 @@ <plugin name="accessControl" type="Magento\Quote\Model\QuoteRepository\Plugin\AccessChangeQuoteControl" /> <plugin name="authorization" type="Magento\Quote\Model\QuoteRepository\Plugin\Authorization" /> </type> + <type name="Magento\Quote\Model\Quote"> + <plugin name="updateQuoteStoreId" type="Magento\Quote\Model\Quote\Plugin\UpdateQuoteStoreId" /> + </type> </config> diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php index 373ad64ba39d4..1054706819e95 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php @@ -5,8 +5,13 @@ */ namespace Magento\Quote\Api; +use Magento\Catalog\Model\Product; use Magento\CatalogInventory\Api\StockRegistryInterface; use Magento\CatalogInventory\Model\Stock; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\QuoteIdMask; +use Magento\Quote\Model\QuoteIdMaskFactory; +use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\ObjectManager; use Magento\TestFramework\TestCase\WebapiAbstract; @@ -40,14 +45,14 @@ protected function setUp(): void */ public function testGetList() { - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->load('test_order_item_with_items', 'reserved_order_id'); $cartId = $quote->getId(); - /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ - $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + /** @var QuoteIdMask $quoteIdMask */ + $quoteIdMask = Bootstrap::getObjectManager() + ->create(QuoteIdMaskFactory::class) ->create(); $quoteIdMask->load($cartId, 'quote_id'); //Use masked cart Id @@ -92,17 +97,17 @@ public function testGetList() */ public function testAddItem() { - /** @var \Magento\Catalog\Model\Product $product */ - $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class)->load(2); + /** @var Product $product */ + $product = $this->objectManager->create(Product::class)->load(2); $productSku = $product->getSku(); - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->load('test_order_1', 'reserved_order_id'); $cartId = $quote->getId(); - /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ - $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + /** @var QuoteIdMask $quoteIdMask */ + $quoteIdMask = Bootstrap::getObjectManager() + ->create(QuoteIdMaskFactory::class) ->create(); $quoteIdMask->load($cartId, 'quote_id'); //Use masked cart Id @@ -141,20 +146,20 @@ public function testAddItem() */ public function testRemoveItem() { - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->load('test_order_item_with_items', 'reserved_order_id'); $cartId = $quote->getId(); - /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ - $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + /** @var QuoteIdMask $quoteIdMask */ + $quoteIdMask = Bootstrap::getObjectManager() + ->create(QuoteIdMaskFactory::class) ->create(); $quoteIdMask->load($cartId, 'quote_id'); //Use masked cart Id $cartId = $quoteIdMask->getMaskedId(); - $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class); + $product = $this->objectManager->create(Product::class); $productId = $product->getIdBySku('simple_one'); $product->load($productId); $itemId = $quote->getItemByProduct($product)->getId(); @@ -175,7 +180,7 @@ public function testRemoveItem() "itemId" => $itemId, ]; $this->assertTrue($this->_webApiCall($serviceInfo, $requestData)); - $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); + $quote = $this->objectManager->create(Quote::class); $quote->load('test_order_item_with_items', 'reserved_order_id'); $this->assertFalse($quote->hasProductId($productId)); } @@ -189,20 +194,20 @@ public function testRemoveItem() public function testUpdateItem(array $stockData, string $errorMessage = null) { $this->updateStockData('simple_one', $stockData); - /** @var \Magento\Quote\Model\Quote $quote */ - $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); $quote->load('test_order_item_with_items', 'reserved_order_id'); $cartId = $quote->getId(); - /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ - $quoteIdMask = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + /** @var QuoteIdMask $quoteIdMask */ + $quoteIdMask = Bootstrap::getObjectManager() + ->create(QuoteIdMaskFactory::class) ->create(); $quoteIdMask->load($cartId, 'quote_id'); //Use masked cart Id $cartId = $quoteIdMask->getMaskedId(); - $product = $this->objectManager->create(\Magento\Catalog\Model\Product::class); + $product = $this->objectManager->create(Product::class); $productId = $product->getIdBySku('simple_one'); $product->load($productId); $itemId = $quote->getItemByProduct($product)->getId(); @@ -229,7 +234,7 @@ public function testUpdateItem(array $stockData, string $errorMessage = null) $this->expectExceptionMessage($errorMessage); } $this->_webApiCall($serviceInfo, $requestData); - $quote = $this->objectManager->create(\Magento\Quote\Model\Quote::class); + $quote = $this->objectManager->create(Quote::class); $quote->load('test_order_item_with_items', 'reserved_order_id'); $this->assertTrue($quote->hasProductId(1)); $item = $quote->getItemByProduct($product); @@ -237,6 +242,62 @@ public function testUpdateItem(array $stockData, string $errorMessage = null) $this->assertEquals($itemId, $item->getItemId()); } + /** + * Verifies that store id for quote and quote item is being changed accordingly to the requested store code + * + * @magentoApiDataFixture Magento/Checkout/_files/quote_with_items_saved.php + * @magentoApiDataFixture Magento/Store/_files/second_store.php + */ + public function testUpdateItemWithChangingStoreId() + { + /** @var Quote $quote */ + $quote = $this->objectManager->create(Quote::class); + $quote->load('test_order_item_with_items', 'reserved_order_id'); + $cartId = $quote->getId(); + + /** @var QuoteIdMask $quoteIdMask */ + $quoteIdMask = Bootstrap::getObjectManager() + ->create(QuoteIdMaskFactory::class) + ->create(); + $quoteIdMask->load($cartId, 'quote_id'); + $cartId = $quoteIdMask->getMaskedId(); + + $product = $this->objectManager->create(Product::class); + $productId = $product->getIdBySku('simple'); + $product->load($productId); + $itemId = $quote->getItemByProduct($product)->getId(); + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH . $cartId . '/items/' . $itemId, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $requestData['cartItem']['qty'] = 5; + if (TESTS_WEB_API_ADAPTER === self::ADAPTER_SOAP) { + $requestData['cartItem'] += [ + 'quote_id' => $cartId, + 'itemId' => $itemId, + ]; + } + $this->_webApiCall($serviceInfo, $requestData, null, 'fixture_second_store'); + $quote = $this->objectManager->create(Quote::class); + $quote->load('test_order_item_with_items', 'reserved_order_id'); + $this->assertTrue($quote->hasProductId(1)); + $item = $quote->getItemByProduct($product); + /** @var StoreManagerInterface $storeManager */ + $storeManager = $this->objectManager->get(StoreManagerInterface::class); + $storeId = $storeManager->getStore('fixture_second_store') + ->getId(); + $this->assertEquals($storeId, $quote->getStoreId()); + $this->assertEquals($storeId, $item->getStoreId()); + } + /** * @return array */ From 60e6c687fd2aa57734a519a983ab81e1ee381427 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Tue, 15 Dec 2020 14:28:46 +0200 Subject: [PATCH 260/346] MC-39104: 2 error messages in Cart when product is out of stock --- .../Model/Quote/Item/QuantityValidator.php | 4 +- .../Initializer/QuantityValidatorTest.php | 50 ++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php index b4754eea5c064..12d9206ebff17 100644 --- a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php +++ b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php @@ -157,7 +157,9 @@ public function validate(Observer $observer) if ($stockStatus->getStockStatus() === Stock::STOCK_OUT_OF_STOCK || $parentStockStatus && $parentStockStatus->getStockStatus() == Stock::STOCK_OUT_OF_STOCK ) { - if (!$quoteItem->getStockStateResult() && !$quoteItem->getStockStateResult()->getHasError()) { + $hasError = $quoteItem->getStockStateResult() + ? $quoteItem->getStockStateResult()->getHasError() : false; + if (!$hasError) { $quoteItem->addErrorInfo( 'cataloginventory', Data::ERROR_QTY, diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php index edc22a008c554..0a1eee76d6960 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php @@ -153,7 +153,7 @@ protected function setUp(): void ->getMock(); $this->storeMock = $this->createMock(Store::class); $this->quoteItemMock = $this->getMockBuilder(Item::class) - ->addMethods(['getProductId', 'getHasError']) + ->addMethods(['getProductId', 'getHasError', 'getStockStateResult']) ->onlyMethods( [ 'getQuote', @@ -460,6 +460,54 @@ public function testException() $this->quantityValidator->validate($this->observerMock); } + /** + * This tests the scenario when the error is in the quote item already + * + * @return void + */ + public function testValidateOutStockWithAlreadyErrorInQuoteItem(): void + { + $this->createInitialStub(1); + $resultMock = $this->getMockBuilder(DataObject::class) + ->addMethods(['checkQtyIncrements', 'getMessage', 'getQuoteMessage', 'getHasError']) + ->getMock(); + $resultMock->method('getHasError') + ->willReturn(true); + $this->stockRegistryMock->method('getStockItem') + ->willReturn($this->stockItemMock); + $this->stockRegistryMock->expects($this->at(1)) + ->method('getStockStatus') + ->willReturn($this->stockStatusMock); + $this->quoteItemMock->method('getParentItem') + ->willReturn($this->parentItemMock); + $this->quoteItemMock->method('getStockStateResult') + ->willReturn($resultMock); + $this->stockRegistryMock->expects($this->at(2)) + ->method('getStockStatus') + ->willReturn($this->parentStockItemMock); + $this->parentStockItemMock->method('getStockStatus') + ->willReturn(0); + $this->stockStatusMock->expects($this->atLeastOnce()) + ->method('getStockStatus') + ->willReturn(1); + $this->quoteItemMock->expects($this->never()) + ->method('addErrorInfo') + ->with( + 'cataloginventory', + Data::ERROR_QTY, + __('This product is out of stock.') + ); + $this->quoteMock->expects($this->once()) + ->method('addErrorInfo') + ->with( + 'stock', + 'cataloginventory', + Data::ERROR_QTY, + __('Some of the products are out of stock.') + ); + $this->quantityValidator->validate($this->observerMock); + } + /** * @param $qty * @param $hasError From c2698626c27275a50a248d25092b1b93c9c1b3b3 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Mon, 14 Dec 2020 12:16:23 -0600 Subject: [PATCH 261/346] MC-39827: Problem on Coupon Report with splited database - Fix sql error when trying to view coupon report with split database setup --- .../Model/ResourceModel/Report/Rule.php | 5 ++- .../Model/ResourceModel/Report/RuleTest.php | 21 +++++++---- .../Model/ResourceModel/Report/RuleTest.php | 37 +++++++++++++++++++ 3 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/RuleTest.php diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/Report/Rule.php b/app/code/Magento/SalesRule/Model/ResourceModel/Report/Rule.php index fb3f420a325e6..907d2c0494364 100644 --- a/app/code/Magento/SalesRule/Model/ResourceModel/Report/Rule.php +++ b/app/code/Magento/SalesRule/Model/ResourceModel/Report/Rule.php @@ -90,8 +90,9 @@ public function aggregate($from = null, $to = null) */ public function getUniqRulesNamesList() { - $connection = $this->getConnection(); - $tableName = $this->getTable('salesrule_coupon_aggregated'); + $resourceModel = $this->_createdatFactory->create(); + $connection = $resourceModel->getConnection(); + $tableName = $resourceModel->getMainTable(); $select = $connection->select()->from( $tableName, new \Zend_Db_Expr('DISTINCT rule_name') diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/ResourceModel/Report/RuleTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/ResourceModel/Report/RuleTest.php index 1a302747fe454..9cb9767f47932 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/ResourceModel/Report/RuleTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/ResourceModel/Report/RuleTest.php @@ -7,13 +7,13 @@ namespace Magento\SalesRule\Test\Unit\Model\ResourceModel\Report; -use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\Pdo\Mysql; use Magento\Framework\DB\Select; use Magento\Framework\DB\Select\SelectRenderer; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Reports\Model\FlagFactory; use Magento\SalesRule\Model\ResourceModel\Report\Rule; +use Magento\SalesRule\Model\ResourceModel\Report\Rule\Createdat; use Magento\SalesRule\Model\ResourceModel\Report\Rule\CreatedatFactory; use Magento\SalesRule\Model\ResourceModel\Report\Rule\UpdatedatFactory; use PHPUnit\Framework\TestCase; @@ -84,14 +84,20 @@ function ($value) { [$this, 'fetchAllCallback'] ); - $resourceMock = $this->createMock(ResourceConnection::class); - $resourceMock->expects($this->any())->method('getConnection')->willReturn($connectionMock); - $resourceMock->expects($this->once())->method('getTableName')->willReturn(self::TABLE_NAME); - $flagFactory = $this->createMock(FlagFactory::class); - $createdatFactoryMock = $this->createPartialMock( + + $createdatResourceModel = $this->createConfiguredMock( + Createdat::class, + [ + 'getConnection' => $connectionMock, + 'getMainTable' => self::TABLE_NAME, + ] + ); + $createdatFactoryMock = $this->createConfiguredMock( CreatedatFactory::class, - ['create'] + [ + 'create' => $createdatResourceModel + ] ); $updatedatFactoryMock = $this->createPartialMock( UpdatedatFactory::class, @@ -102,7 +108,6 @@ function ($value) { $model = $objectHelper->getObject( Rule::class, [ - 'resource' => $resourceMock, 'reportsFlagFactory' => $flagFactory, 'createdatFactory' => $createdatFactoryMock, 'updatedatFactory' => $updatedatFactoryMock diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/RuleTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/RuleTest.php new file mode 100644 index 0000000000000..58b82375cfbe9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/ResourceModel/Report/RuleTest.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\SalesRule\Model\ResourceModel\Report; + +use Magento\Sales\Model\Order; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Test for salesrule report model + */ +class RuleTest extends TestCase +{ + /** + * @magentoDataFixture Magento/SalesRule/_files/order_with_coupon.php + */ + public function testGetUniqRulesNamesList() + { + $ruleName = uniqid('cart_price_rule_'); + $orderIncrementId = '100000001'; + $objectManager = Bootstrap::getObjectManager(); + /** @var Order $order */ + $order = $objectManager->create(Order::class); + $order->loadByIncrementId($orderIncrementId) + ->setCouponRuleName($ruleName) + ->save(); + /** @var Rule $reportResource */ + $reportResource = $objectManager->create(Rule::class); + $reportResource->aggregate(); + $this->assertContains($ruleName, $reportResource->getUniqRulesNamesList()); + } +} From cece001e28889b66b2b36daf129fa20bf6ef2c17 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 15 Dec 2020 16:46:20 +0200 Subject: [PATCH 262/346] MC-39911: [MFTF] AdminFPTIncludingAndExcludingTaxVisibleOnNegotiableQuotePageTest fails because of bad design --- ...uctAttributesFilteredByCodeActionGroup.xml | 35 +++++++++++ .../Test/Mftf/Helper/CatalogHelper.php | 61 +++++++++++++++++++ .../AdminProductAttributeGridSection.xml | 1 + .../Section/AdminDataGridTableSection.xml | 1 + .../Mftf/Data/FixedProductAttributeData.xml | 4 +- .../Weee/Test/Mftf/Data/FrontendLabelData.xml | 15 +++++ 6 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php create mode 100644 app/code/Magento/Weee/Test/Mftf/Data/FrontendLabelData.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml new file mode 100644 index 0000000000000..4d4314827da1c --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteAllProductAttributesFilteredByCodeActionGroup"> + <annotations> + <description>Open product attributes grid filter it by attribute code and delete all found attributes one by one.</description> + </annotations> + <arguments> + <argument name="codeFilter" type="string" defaultValue="fake-code"/> + </arguments> + + <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> + <!-- It sometimes is loading too long for default 10s --> + <waitForPageLoad time="60" stepKey="waitForPageFullyLoaded"/> + <click selector="{{AdminProductAttributeGridSection.ResetFilter}}" stepKey="clearExistingFilters"/> + <fillField selector="{{AdminProductAttributeGridSection.attributeCodeFilter}}" userInput="{{codeFilter}}" stepKey="fillAttributeCodeFilterField"/> + <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="applyGridFilter"/> + <helper class="\Magento\Catalog\Test\Mftf\Helper\CatalogHelper" method="deleteAllProductAttributesOneByOne" stepKey="deleteAllProductAttributesOneByOne"> + <argument name="firstNotEmptyRow">{{AdminDataGridTableSection.firstNotEmptyRow2}}</argument> + <argument name="modalAcceptButton">{{AdminConfirmationModalSection.ok}}</argument> + <argument name="deleteButton">{{AdminMainActionsSection.delete}}</argument> + <argument name="successMessageContainer">{{AdminMessagesSection.success}}</argument> + <argument name="successMessage">You deleted the product attribute.</argument> + </helper> + <waitForElementVisible selector="{{AdminDataGridTableSection.dataGridEmpty}}" stepKey="waitDataGridEmptyMessageAppears"/> + <see selector="{{AdminDataGridTableSection.dataGridEmpty}}" userInput="We couldn't find any records." stepKey="assertDataGridEmptyMessage"/> + <click selector="{{AdminProductAttributeGridSection.ResetFilter}}" stepKey="clearExistingFiltersAgain"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php b/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php new file mode 100644 index 0000000000000..2ac8ef35dc8a7 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Test\Mftf\Helper; + +use Facebook\WebDriver\Remote\RemoteWebDriver as FacebookWebDriver; +use Facebook\WebDriver\WebDriverBy; +use Magento\FunctionalTestingFramework\Helper\Helper; +use Magento\FunctionalTestingFramework\Module\MagentoWebDriver; + +/** + * Class for MFTF helpers for Catalog module. + */ +class CatalogHelper extends Helper +{ + /** + * Delete all product attributes one by one. + * + * @param string $firstNotEmptyRow + * @param string $modalAcceptButton + * @param string $deleteButton + * @param string $successMessageContainer + * @param string $successMessage + * @retrun void + */ + public function deleteAllProductAttributesOneByOne( + string $firstNotEmptyRow, + string $modalAcceptButton, + string $deleteButton, + string $successMessageContainer, + string $successMessage + ): void { + try { + /** @var MagentoWebDriver $webDriver */ + $magentoWebDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); + /** @var FacebookWebDriver $webDriver */ + $webDriver = $magentoWebDriver->webDriver; + $rows = $webDriver->findElements(WebDriverBy::cssSelector($firstNotEmptyRow)); + while (!empty($rows)) { + $rows[0]->click(); + $magentoWebDriver->waitForPageLoad(30); + $magentoWebDriver->click($deleteButton); + $magentoWebDriver->waitForPageLoad(30); + $magentoWebDriver->waitForElementVisible($modalAcceptButton, 10); + $magentoWebDriver->waitForPageLoad(60); + $magentoWebDriver->click($modalAcceptButton); + $magentoWebDriver->waitForPageLoad(60); + $magentoWebDriver->waitForLoadingMaskToDisappear(); + $magentoWebDriver->waitForElementVisible($successMessageContainer, 10); + $magentoWebDriver->see($successMessage, $successMessageContainer); + $rows = $webDriver->findElements(WebDriverBy::cssSelector($firstNotEmptyRow)); + } + } catch (\Exception $e) { + $this->fail($e->getMessage()); + } + } +} diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml index e4b33ac795559..295f6da6cf215 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml @@ -17,6 +17,7 @@ <element name="FirstRow" type="button" selector="//*[@id='attributeGrid_table']/tbody/tr[1]" timeout="30"/> <element name="FilterByAttributeCode" type="input" selector="#attributeGrid_filter_attribute_code"/> <element name="attributeLabelFilter" type="input" selector="//input[@name='frontend_label']"/> + <element name="attributeCodeFilter" type="input" selector=".data-grid-filters input[name='attribute_code']"/> <element name="attributeCodeColumn" type="text" selector="//div[@id='attributeGrid']//td[contains(@class,'col-attr-code col-attribute_code')]"/> <element name="defaultLabelColumn" type="text" selector="//div[@id='attributeGrid']//table[@id='attributeGrid_table']//tbody//td[contains(@class,'col-label col-frontend_label')]"/> <element name="isVisibleColumn" type="text" selector="//div[@id='attributeGrid']//td[contains(@class,'a-center col-is_visible')]"/> diff --git a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml index c5b000259e265..d2d39076bcfbb 100644 --- a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml +++ b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml @@ -22,5 +22,6 @@ <element name="rowTemplateStrict" type="block" selector="//tbody/tr[td[*[text()[normalize-space()='{{text}}']]]]" parameterized="true" /> <element name="rowTemplate" type="block" selector="//tbody/tr[td[*[contains(.,normalize-space('{{text}}'))]]]" parameterized="true" timeout="30" /> <element name="firstNotEmptyRow" type="block" selector="table.data-grid tbody tr[data-role=row]:not(.data-grid-tr-no-data):nth-of-type(1)" timeout="30"/> + <element name="firstNotEmptyRow2" type="block" selector="table.data-grid tbody tr:not(.data-grid-tr-no-data):nth-of-type(1)" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml b/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml index b8b45d84242c9..b5736479fac42 100644 --- a/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml +++ b/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml @@ -9,12 +9,12 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="productFPTAttribute" type="ProductAttribute"> - <data key="attribute_code" unique="suffix">attribute</data> + <data key="attribute_code" unique="suffix">weee_attribute</data> <data key="is_unique">true</data> <data key="frontend_input">weee</data> <data key="is_used_in_grid">true</data> <data key="is_visible_in_grid">true</data> <data key="is_filterable_in_grid">true</data> - <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> + <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabelWeee</requiredEntity> </entity> </entities> diff --git a/app/code/Magento/Weee/Test/Mftf/Data/FrontendLabelData.xml b/app/code/Magento/Weee/Test/Mftf/Data/FrontendLabelData.xml new file mode 100644 index 0000000000000..7c362ba0ee303 --- /dev/null +++ b/app/code/Magento/Weee/Test/Mftf/Data/FrontendLabelData.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="ProductAttributeFrontendLabelWeee" type="FrontendLabel"> + <data key="store_id">0</data> + <data key="label" unique="suffix">weee-attribute</data> + </entity> +</entities> From f612499f4177ea79f553b13d9e3458e9cdd65a55 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 15 Dec 2020 19:19:40 +0200 Subject: [PATCH 263/346] MC-39911: [MFTF] AdminFPTIncludingAndExcludingTaxVisibleOnNegotiableQuotePageTest fails because of bad design --- ...AllProductAttributesFilteredByCodeActionGroup.xml | 2 +- .../Catalog/Test/Mftf/Helper/CatalogHelper.php | 12 +++++------- .../Test/Mftf/Data/FixedProductAttributeData.xml | 11 ++++++++++- .../AdminFixedTaxValSavedForSpecificWebsiteTest.xml | 2 +- .../AdminRemoveProductWeeeAttributeOptionTest.xml | 2 +- ...ionInShoppingCartForCustomerPhysicalQuoteTest.xml | 2 +- ...tionInShoppingCartForCustomerVirtualQuoteTest.xml | 2 +- ...mationInShoppingCartForGuestPhysicalQuoteTest.xml | 2 +- ...rmationInShoppingCartForGuestVirtualQuoteTest.xml | 2 +- 9 files changed, 22 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml index 4d4314827da1c..12249d6cb946b 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml @@ -22,7 +22,7 @@ <fillField selector="{{AdminProductAttributeGridSection.attributeCodeFilter}}" userInput="{{codeFilter}}" stepKey="fillAttributeCodeFilterField"/> <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="applyGridFilter"/> <helper class="\Magento\Catalog\Test\Mftf\Helper\CatalogHelper" method="deleteAllProductAttributesOneByOne" stepKey="deleteAllProductAttributesOneByOne"> - <argument name="firstNotEmptyRow">{{AdminDataGridTableSection.firstNotEmptyRow2}}</argument> + <argument name="notEmptyRow">{{AdminDataGridTableSection.firstNotEmptyRow2}}</argument> <argument name="modalAcceptButton">{{AdminConfirmationModalSection.ok}}</argument> <argument name="deleteButton">{{AdminMainActionsSection.delete}}</argument> <argument name="successMessageContainer">{{AdminMessagesSection.success}}</argument> diff --git a/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php b/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php index 2ac8ef35dc8a7..f72a41b46298e 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php +++ b/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php @@ -28,7 +28,7 @@ class CatalogHelper extends Helper * @retrun void */ public function deleteAllProductAttributesOneByOne( - string $firstNotEmptyRow, + string $notEmptyRow, string $modalAcceptButton, string $deleteButton, string $successMessageContainer, @@ -39,20 +39,18 @@ public function deleteAllProductAttributesOneByOne( $magentoWebDriver = $this->getModule('\Magento\FunctionalTestingFramework\Module\MagentoWebDriver'); /** @var FacebookWebDriver $webDriver */ $webDriver = $magentoWebDriver->webDriver; - $rows = $webDriver->findElements(WebDriverBy::cssSelector($firstNotEmptyRow)); - while (!empty($rows)) { - $rows[0]->click(); + $gridRows = $webDriver->findElements(WebDriverBy::cssSelector($notEmptyRow)); + while (!empty($gridRows)) { + $gridRows[0]->click(); $magentoWebDriver->waitForPageLoad(30); $magentoWebDriver->click($deleteButton); $magentoWebDriver->waitForPageLoad(30); $magentoWebDriver->waitForElementVisible($modalAcceptButton, 10); - $magentoWebDriver->waitForPageLoad(60); $magentoWebDriver->click($modalAcceptButton); $magentoWebDriver->waitForPageLoad(60); - $magentoWebDriver->waitForLoadingMaskToDisappear(); $magentoWebDriver->waitForElementVisible($successMessageContainer, 10); $magentoWebDriver->see($successMessage, $successMessageContainer); - $rows = $webDriver->findElements(WebDriverBy::cssSelector($firstNotEmptyRow)); + $gridRows = $webDriver->findElements(WebDriverBy::cssSelector($notEmptyRow)); } } catch (\Exception $e) { $this->fail($e->getMessage()); diff --git a/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml b/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml index b5736479fac42..071f96bb65266 100644 --- a/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml +++ b/app/code/Magento/Weee/Test/Mftf/Data/FixedProductAttributeData.xml @@ -8,7 +8,16 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="productFPTAttribute" type="ProductAttribute"> + <entity name="productFPTAttribute" type="ProductAttribute" deprecated="Use FPTProductAttribute instead"> + <data key="attribute_code" unique="suffix">attribute</data> + <data key="is_unique">true</data> + <data key="frontend_input">weee</data> + <data key="is_used_in_grid">true</data> + <data key="is_visible_in_grid">true</data> + <data key="is_filterable_in_grid">true</data> + <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> + </entity> + <entity name="FPTProductAttribute" type="ProductAttribute"> <data key="attribute_code" unique="suffix">weee_attribute</data> <data key="is_unique">true</data> <data key="frontend_input">weee</data> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml index 0f4a7f9a55d26..ccbd431848dbc 100644 --- a/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml +++ b/app/code/Magento/Weee/Test/Mftf/Test/AdminFixedTaxValSavedForSpecificWebsiteTest.xml @@ -22,7 +22,7 @@ <before> <!-- Create product attribute and add it to default attribute set />--> <comment userInput="Create product attribute and add it to default attribute set" stepKey="createAttrAndAddToDefaultAttrSet"/> - <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="FPTProductAttribute" stepKey="createProductFPTAttribute"/> <createData entity="AddToDefaultSet" stepKey="addToDefaultAttributeSet"> <requiredEntity createDataKey="createProductFPTAttribute"/> </createData> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml index 0d7c21b6efffc..4e70c9ba87d64 100644 --- a/app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml +++ b/app/code/Magento/Weee/Test/Mftf/Test/AdminRemoveProductWeeeAttributeOptionTest.xml @@ -18,7 +18,7 @@ <group value="weee"/> </annotations> <before> - <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="FPTProductAttribute" stepKey="createProductFPTAttribute"/> <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> <requiredEntity createDataKey="createProductFPTAttribute"/> </createData> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerPhysicalQuoteTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerPhysicalQuoteTest.xml index e78036458301b..833f619888bfb 100644 --- a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerPhysicalQuoteTest.xml +++ b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerPhysicalQuoteTest.xml @@ -27,7 +27,7 @@ <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> <!-- Fixed Product Tax attribute is created and added to default attribute set --> - <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="FPTProductAttribute" stepKey="createProductFPTAttribute"/> <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> <requiredEntity createDataKey="createProductFPTAttribute"/> </createData> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerVirtualQuoteTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerVirtualQuoteTest.xml index dda125835110a..8e8667cb7e13d 100644 --- a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerVirtualQuoteTest.xml +++ b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForCustomerVirtualQuoteTest.xml @@ -27,7 +27,7 @@ <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> <!-- Fixed Product Tax attribute is created and added to default attribute set --> - <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="FPTProductAttribute" stepKey="createProductFPTAttribute"/> <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> <requiredEntity createDataKey="createProductFPTAttribute"/> </createData> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml index 74ba7c1f2bff3..3a3f9c7e8931a 100644 --- a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml +++ b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestPhysicalQuoteTest.xml @@ -27,7 +27,7 @@ <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> <!-- Fixed Product Tax attribute is created and added to default attribute set --> - <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="FPTProductAttribute" stepKey="createProductFPTAttribute"/> <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> <requiredEntity createDataKey="createProductFPTAttribute"/> </createData> diff --git a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestVirtualQuoteTest.xml b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestVirtualQuoteTest.xml index 495b9a990a465..0d54991f84395 100644 --- a/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestVirtualQuoteTest.xml +++ b/app/code/Magento/Weee/Test/Mftf/Test/StorefrontFPTTaxInformationInShoppingCartForGuestVirtualQuoteTest.xml @@ -27,7 +27,7 @@ <!-- Tax Rule is created based on default tax rates (Stores>Tax Rule) US-CA-*-Rate 1 = 8.2500 US-NY-*-Rate 1 = 8.3750 --> <createData entity="SimpleTaxRule" stepKey="createTaxRule"/> <!-- Fixed Product Tax attribute is created and added to default attribute set --> - <createData entity="productFPTAttribute" stepKey="createProductFPTAttribute"/> + <createData entity="FPTProductAttribute" stepKey="createProductFPTAttribute"/> <createData entity="AddToDefaultSet" stepKey="addFPTToAttributeSet"> <requiredEntity createDataKey="createProductFPTAttribute"/> </createData> From 58f9f29843f1fcb07a642f270c0d8cb042bf0075 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Tue, 15 Dec 2020 16:48:58 -0600 Subject: [PATCH 264/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../Magento/UrlRewrite/Model/UrlRewrite.php | 88 ++++++++++++++++--- 1 file changed, 77 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index 363a3388daab0..3722c27a1b312 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -7,9 +7,6 @@ namespace Magento\UrlRewrite\Model; -use Magento\Catalog\Model\Category; -use Magento\Catalog\Model\Product; -use Magento\Cms\Model\Page; use Magento\Framework\App\ObjectManager; use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\EntityManager\EventManager; @@ -61,6 +58,11 @@ class UrlRewrite extends AbstractModel */ private $entityToCacheTagMap; + /** + * @var UrlFinderInterface + */ + private $urlFinder; + /** * UrlRewrite constructor. * @@ -72,6 +74,7 @@ class UrlRewrite extends AbstractModel * @param Json|null $serializer * @param CacheContext|null $cacheContext * @param EventManager|null $eventManager + * @param UrlFinderInterface|null $urlFinder * @param array $entityToCacheTagMap */ public function __construct( @@ -83,12 +86,14 @@ public function __construct( Json $serializer = null, CacheContext $cacheContext = null, EventManager $eventManager = null, + UrlFinderInterface $urlFinder = null, array $entityToCacheTagMap = [] ) { $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); $this->cacheContext = $cacheContext ?: ObjectManager::getInstance()->get(CacheContext::class); $this->eventManager = $eventManager ?: ObjectManager::getInstance()->get(EventManager::class); + $this->urlFinder = $urlFinder ?: ObjectManager::getInstance()->get(UrlFinderInterface::class); $this->entityToCacheTagMap = $entityToCacheTagMap; parent::__construct($context, $registry, $resource, $resourceCollection, $data); } @@ -131,30 +136,91 @@ public function setMetadata($metadata) } /** - * Clean cache for the entity which was affected by updating UrlRewrite + * Gets final target UrlRewrite for custom rewrite record * - * @param $entityType - * @param $entityId + * @param string $path + * @param int $storeId + * @return UrlRewrite|null + */ + private function getFinalTargetUrlRewrite(string $path, int $storeId) { + $urlRewriteTarget = $this->urlFinder->findOneByData( + [ + 'request_path' => $path, + 'store_id' => $storeId + ] + ); + + while ($urlRewriteTarget && $urlRewriteTarget->getRedirectType() > 0) { + $urlRewriteTarget = $this->urlFinder->findOneByData( + [ + 'request_path' => $urlRewriteTarget->getTargetPath(), + 'store_id' => $urlRewriteTarget->getStoreId() + ] + ); + } + + return $urlRewriteTarget; + } + + /** + * Clean the cache for entities affected by current rewrite */ - private function cleanCacheForEntity($entityType, $entityId) + private function cleanEntitiesCache() { + if ($this->getEntityType() === Rewrite::ENTITY_TYPE_CUSTOM) { + $urlRewrite = $this->getFinalTargetUrlRewrite( + $this->getTargetPath(), + (int)$this->getStoreId() + ); + + if ($urlRewrite) { + $this->cleanCacheForEntity($urlRewrite->getEntityType(), (int) $urlRewrite->getEntityId()); + } + + if ($this->getOrigData() && $this->getOrigData('target_path') !== $this->getTargetPath()) { + $origUrlRewrite = $this->getFinalTargetUrlRewrite( + $this->getOrigData('target_path'), + (int)$this->getOrigData('store_id') + ); + + if ($origUrlRewrite) { + $this->cleanCacheForEntity($origUrlRewrite->getEntityType(), (int) $origUrlRewrite->getEntityId()); + } + } + } else { + $this->cleanCacheForEntity($this->getEntityType(), (int) $this->getEntityId()); + } + } + + /** + * Clean cache for specified entity type by id + * + * @param string $entityType + * @param int $entityId + */ + private function cleanCacheForEntity(string $entityType, int $entityId) { - if ($entityType !== Rewrite::ENTITY_TYPE_CUSTOM && array_key_exists($entityType, $this->entityToCacheTagMap)) { + if (array_key_exists($entityType, $this->entityToCacheTagMap)) { $cacheKey = $this->entityToCacheTagMap[$entityType]; - $this->cacheContext->registerEntities($cacheKey, [$entityId]); $this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]); } } + /** + * @inheritdoc + */ public function afterDelete() { - $this->cleanCacheForEntity($this->getEntityType(), $this->getEntityId()); + $this->cleanEntitiesCache(); return parent::afterDelete(); } + /** + * @inheritdoc + */ public function afterSave() { - $this->cleanCacheForEntity($this->getEntityType(), $this->getEntityId()); + $this->cleanEntitiesCache(); return parent::afterSave(); } } From d3d41033af551138433d2e413f2f5b378884815b Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Tue, 15 Dec 2020 18:41:43 -0600 Subject: [PATCH 265/346] MC-39861: Customer is redirected to the blank page after using PayPal WPPHS payment on checkout --- .../Controller/Hostedpro/ReturnAction.php | 6 +-- .../Plugin/TransparentSessionChecker.php | 16 +++++- .../Controller/Hostedpro/ReturnActionTest.php | 54 +++++++++++++++++++ 3 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php diff --git a/app/code/Magento/Paypal/Controller/Hostedpro/ReturnAction.php b/app/code/Magento/Paypal/Controller/Hostedpro/ReturnAction.php index bb8b5f8fa0b46..dbaf432878de9 100644 --- a/app/code/Magento/Paypal/Controller/Hostedpro/ReturnAction.php +++ b/app/code/Magento/Paypal/Controller/Hostedpro/ReturnAction.php @@ -26,11 +26,7 @@ class ReturnAction extends Action implements CsrfAwareActionInterface, HttpPostA */ public function execute() { - $session = $this->_objectManager->get(\Magento\Checkout\Model\Session::class); - //TODO: some actions with order - if ($session->getLastRealOrderId()) { - $this->_redirect('checkout/onepage/success'); - } + $this->_redirect('checkout/onepage/success'); } /** diff --git a/app/code/Magento/Paypal/Plugin/TransparentSessionChecker.php b/app/code/Magento/Paypal/Plugin/TransparentSessionChecker.php index 5157ba3208fb7..d53fd183c1942 100644 --- a/app/code/Magento/Paypal/Plugin/TransparentSessionChecker.php +++ b/app/code/Magento/Paypal/Plugin/TransparentSessionChecker.php @@ -15,7 +15,13 @@ */ class TransparentSessionChecker { - private const TRANSPARENT_REDIRECT_PATH = 'paypal/transparent/redirect'; + /** + * @var string[] + */ + private $disableSessionUrls = [ + 'paypal/transparent/redirect', + 'paypal/hostedpro/return', + ]; /** * @var Http @@ -45,6 +51,12 @@ public function afterCheck(SessionStartChecker $subject, bool $result): bool return false; } - return strpos((string)$this->request->getPathInfo(), self::TRANSPARENT_REDIRECT_PATH) === false; + foreach ($this->disableSessionUrls as $url) { + if (strpos((string)$this->request->getPathInfo(), $url) !== false) { + return false; + } + } + + return true; } } diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php new file mode 100644 index 0000000000000..d52c2501a565a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Paypal\Controller\Hostedpro; + +use Magento\TestFramework\TestCase\AbstractController; +use Zend\Stdlib\Parameters; + +/** + * Tests PayPal HostedPro return controller. + */ +class ReturnActionTest extends AbstractController +{ + /** + * Tests customer redirect on success page after return from PayPal HostedPro payment. + * + * @SuppressWarnings(PHPMD.Superglobals) + */ + public function testReturnRedirect() + { + $redirectUri = 'paypal/hostedpro/return'; + $this->setRequestUri($redirectUri); + $this->getRequest()->setMethod('POST'); + + $this->dispatch($redirectUri); + $this->assertRedirect($this->stringContains('checkout/onepage/success')); + + $this->assertEmpty( + $_SESSION, + 'Session start has to be skipped for current controller' + ); + } + + /** + * Sets REQUEST_URI into request object. + * + * @param string $requestUri + * @return void + */ + private function setRequestUri(string $requestUri) + { + $request = $this->getRequest(); + $reflection = new \ReflectionClass($request); + $property = $reflection->getProperty('requestUri'); + $property->setAccessible(true); + $property->setValue($request, null); + + $request->setServer(new Parameters(['REQUEST_URI' => $requestUri])); + } +} From ad5f3fa48e0402702d0b1339f8737028dc8aa27c Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 16 Dec 2020 11:36:31 +0200 Subject: [PATCH 266/346] MC-39765: No such entity with addressId, occurs randomly on visitors browser. System Log Generated --- .../Observer/EmulateCustomerObserver.php | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php index 8429eabd19e8a..0b978b9822345 100644 --- a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php +++ b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php @@ -6,6 +6,7 @@ namespace Magento\Persistent\Observer; use Magento\Framework\Event\ObserverInterface; +use Magento\Framework\Exception\NoSuchEntityException; /** * Class EmulateCustomer @@ -86,9 +87,9 @@ public function execute(\Magento\Framework\Event\Observer $observer) /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ $customer = $this->customerRepository->getById($this->_persistentSession->getSession()->getCustomerId()); if ($defaultShipping = $customer->getDefaultShipping()) { - /** @var \Magento\Customer\Model\Data\Address $address */ - $address = $this->addressRepository->getById($defaultShipping); - if ($address) { + $address = $this->getCustomerAddressById($defaultShipping); + + if ($address !== null) { $this->_customerSession->setDefaultTaxShippingAddress( [ 'country_id' => $address->getCountryId(), @@ -102,8 +103,9 @@ public function execute(\Magento\Framework\Event\Observer $observer) } if ($defaultBilling = $customer->getDefaultBilling()) { - $address = $this->addressRepository->getById($defaultBilling); - if ($address) { + $address = $this->getCustomerAddressById($defaultShipping); + + if ($address !== null) { $this->_customerSession->setDefaultTaxBillingAddress([ 'country_id' => $address->getCountryId(), 'region_id' => $address->getRegion() ? $address->getRegionId() : null, @@ -118,4 +120,19 @@ public function execute(\Magento\Framework\Event\Observer $observer) } return $this; } + + /** + * Returns customer address by id + * + * @param int $addressId + * @return \Magento\Customer\Api\Data\AddressInterface|null + */ + private function getCustomerAddressById($addressId) + { + try { + return $this->addressRepository->getById($addressId); + } catch (NoSuchEntityException $exception) { + return null; + } + } } From b2508014d7da9ef4019214a44dcd9c1447397f0e Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Wed, 16 Dec 2020 11:55:49 +0200 Subject: [PATCH 267/346] MC-39911: [MFTF] AdminFPTIncludingAndExcludingTaxVisibleOnNegotiableQuotePageTest fails because of bad design --- ...nDeleteAllProductAttributesFilteredByCodeActionGroup.xml | 2 +- app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php | 6 +++--- .../Test/Mftf/Section/AdminProductAttributeGridSection.xml | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml index 12249d6cb946b..fe5b0ae1a64ce 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminDeleteAllProductAttributesFilteredByCodeActionGroup.xml @@ -19,7 +19,7 @@ <!-- It sometimes is loading too long for default 10s --> <waitForPageLoad time="60" stepKey="waitForPageFullyLoaded"/> <click selector="{{AdminProductAttributeGridSection.ResetFilter}}" stepKey="clearExistingFilters"/> - <fillField selector="{{AdminProductAttributeGridSection.attributeCodeFilter}}" userInput="{{codeFilter}}" stepKey="fillAttributeCodeFilterField"/> + <fillField selector="{{AdminProductAttributeGridSection.FilterByAttributeCode}}" userInput="{{codeFilter}}" stepKey="fillAttributeCodeFilterField"/> <click selector="{{AdminProductAttributeGridSection.Search}}" stepKey="applyGridFilter"/> <helper class="\Magento\Catalog\Test\Mftf\Helper\CatalogHelper" method="deleteAllProductAttributesOneByOne" stepKey="deleteAllProductAttributesOneByOne"> <argument name="notEmptyRow">{{AdminDataGridTableSection.firstNotEmptyRow2}}</argument> diff --git a/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php b/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php index f72a41b46298e..dcba3b1bf68de 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php +++ b/app/code/Magento/Catalog/Test/Mftf/Helper/CatalogHelper.php @@ -20,7 +20,7 @@ class CatalogHelper extends Helper /** * Delete all product attributes one by one. * - * @param string $firstNotEmptyRow + * @param string $notEmptyRow * @param string $modalAcceptButton * @param string $deleteButton * @param string $successMessageContainer @@ -45,10 +45,10 @@ public function deleteAllProductAttributesOneByOne( $magentoWebDriver->waitForPageLoad(30); $magentoWebDriver->click($deleteButton); $magentoWebDriver->waitForPageLoad(30); - $magentoWebDriver->waitForElementVisible($modalAcceptButton, 10); + $magentoWebDriver->waitForElementVisible($modalAcceptButton); $magentoWebDriver->click($modalAcceptButton); $magentoWebDriver->waitForPageLoad(60); - $magentoWebDriver->waitForElementVisible($successMessageContainer, 10); + $magentoWebDriver->waitForElementVisible($successMessageContainer); $magentoWebDriver->see($successMessage, $successMessageContainer); $gridRows = $webDriver->findElements(WebDriverBy::cssSelector($notEmptyRow)); } diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml index 295f6da6cf215..e4b33ac795559 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductAttributeGridSection.xml @@ -17,7 +17,6 @@ <element name="FirstRow" type="button" selector="//*[@id='attributeGrid_table']/tbody/tr[1]" timeout="30"/> <element name="FilterByAttributeCode" type="input" selector="#attributeGrid_filter_attribute_code"/> <element name="attributeLabelFilter" type="input" selector="//input[@name='frontend_label']"/> - <element name="attributeCodeFilter" type="input" selector=".data-grid-filters input[name='attribute_code']"/> <element name="attributeCodeColumn" type="text" selector="//div[@id='attributeGrid']//td[contains(@class,'col-attr-code col-attribute_code')]"/> <element name="defaultLabelColumn" type="text" selector="//div[@id='attributeGrid']//table[@id='attributeGrid_table']//tbody//td[contains(@class,'col-label col-frontend_label')]"/> <element name="isVisibleColumn" type="text" selector="//div[@id='attributeGrid']//td[contains(@class,'a-center col-is_visible')]"/> From b4a14812aff90e5658a9cd6570ba0c2b66d29260 Mon Sep 17 00:00:00 2001 From: Vadim Malesh <51680850+engcom-Charlie@users.noreply.github.com> Date: Wed, 16 Dec 2020 13:59:34 +0200 Subject: [PATCH 268/346] update testCaseId --- .../Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml index 95607a83dd26f..d5dcd7f48b956 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Test/AdminCreateGroupedProductNonDefaultAttributeSetTest.xml @@ -13,6 +13,7 @@ <stories value="Create product"/> <title value="Create Grouped Product when non-default attribute set is chosen"/> <description value="Create Grouped Product with simple when non-default attribute set is chosen"/> + <testCaseId value="MC-39950"/> <severity value="MAJOR"/> <group value="groupedProduct"/> </annotations> From 3bb857f8d60e45a40931bb99085c7d8f841ce922 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 16 Dec 2020 14:44:52 +0200 Subject: [PATCH 269/346] MC-39765: No such entity with addressId, occurs randomly on visitors browser. System Log Generated --- .../Magento/Persistent/Observer/EmulateCustomerObserver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php index 0b978b9822345..c991836a287d2 100644 --- a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php +++ b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php @@ -103,7 +103,7 @@ public function execute(\Magento\Framework\Event\Observer $observer) } if ($defaultBilling = $customer->getDefaultBilling()) { - $address = $this->getCustomerAddressById($defaultShipping); + $address = $this->getCustomerAddressById($defaultBilling); if ($address !== null) { $this->_customerSession->setDefaultTaxBillingAddress([ From 468383e24bb059e1f25e902a782e51cf03d9f312 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Wed, 16 Dec 2020 15:51:30 +0200 Subject: [PATCH 270/346] MC-39104: 2 error messages in Cart when product is out of stock --- .../CatalogInventory/Model/Quote/Item/QuantityValidator.php | 2 ++ .../Test/NoOptionAvailableToConfigureDisabledProductTest.xml | 4 ++-- .../Magento/Quote/Api/GuestCartItemRepositoryTest.php | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php index 12d9206ebff17..12a48caf62414 100644 --- a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php +++ b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php @@ -165,6 +165,8 @@ public function validate(Observer $observer) Data::ERROR_QTY, __('This product is out of stock.') ); + } else { + $quoteItem->addErrorInfo(null, Data::ERROR_QTY); } $quoteItem->getQuote()->addErrorInfo( 'stock', diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/NoOptionAvailableToConfigureDisabledProductTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/NoOptionAvailableToConfigureDisabledProductTest.xml index e0dae94f13150..b75dd590dbbf1 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/NoOptionAvailableToConfigureDisabledProductTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/NoOptionAvailableToConfigureDisabledProductTest.xml @@ -125,7 +125,7 @@ <actionGroup ref="AdminSetStockStatusActionGroup" stepKey="outOfStockStatus"> <argument name="stockStatus" value="Out of Stock"/> </actionGroup> - + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveSecondProductForm"/> <!-- Go to created customer page --> <comment userInput="Go to created customer page" stepKey="goToCreatedCustomerPage"/> @@ -158,7 +158,7 @@ <waitForPageLoad stepKey="waitForPageLoad"/> <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickToAddProductToOrder"/> <waitForPageLoad stepKey="waitForNewOrderPageLoad"/> - <see userInput="This product is out of stock." stepKey="seeTheErrorMessageDisplayed"/> + <see userInput="There are no source items with the in stock status" stepKey="seeTheErrorMessageDisplayed"/> <actionGroup ref="NavigateToNewOrderPageExistingCustomerActionGroup" stepKey="createNewOrderThirdTime"> <argument name="customer" value="$createCustomer$"/> diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php index 373ad64ba39d4..a9c402096aaf0 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/GuestCartItemRepositoryTest.php @@ -265,7 +265,7 @@ public function updateItemDataProvider(): array 'use_config_backorders' => 0, 'backorders' => Stock::BACKORDERS_NO, ], - 'This product is out of stock.' + 'There are no source items with the in stock status' ], [ [ From 4531c763b5afad4af054bf5dce14669dce0c49ee Mon Sep 17 00:00:00 2001 From: Viktor Rad <vrad@adobe.com> Date: Wed, 16 Dec 2020 07:54:37 -0600 Subject: [PATCH 271/346] MC-38834: Uploading a new logo for print on Logo for HTML Print View settings does not reflect on frontend my account order --- .../ViewModel/Header/LogoPathResolver.php | 69 +++++++++++++++++ .../frontend/layout/sales_order_print.xml | 5 ++ .../layout/sales_order_printcreditmemo.xml | 5 ++ .../layout/sales_order_printinvoice.xml | 5 ++ .../layout/sales_order_printshipment.xml | 5 ++ .../Magento/Theme/Block/Html/Header/Logo.php | 16 ++-- .../Test/Unit/Block/Html/Header/LogoTest.php | 7 +- .../Block/Html/Header/LogoPathResolver.php | 51 +++++++++++++ .../Html/Header/LogoPathResolverInterface.php | 21 ++++++ .../Theme/view/frontend/layout/default.xml | 6 +- .../Sales/Block/Order/PrintOrder/LogoTest.php | 74 +++++++++++++++++++ 11 files changed, 253 insertions(+), 11 deletions(-) create mode 100644 app/code/Magento/Sales/ViewModel/Header/LogoPathResolver.php create mode 100644 app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolver.php create mode 100644 app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolverInterface.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/Block/Order/PrintOrder/LogoTest.php diff --git a/app/code/Magento/Sales/ViewModel/Header/LogoPathResolver.php b/app/code/Magento/Sales/ViewModel/Header/LogoPathResolver.php new file mode 100644 index 0000000000000..c58654e160749 --- /dev/null +++ b/app/code/Magento/Sales/ViewModel/Header/LogoPathResolver.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Sales\ViewModel\Header; + +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Theme\ViewModel\Block\Html\Header\LogoPathResolverInterface; +use Magento\Framework\View\Element\Block\ArgumentInterface; +use Magento\Sales\Model\Order; +use Magento\Framework\Registry; + +/** + * Class for resolving logo path + */ +class LogoPathResolver implements LogoPathResolverInterface, ArgumentInterface +{ + /** + * @var ScopeConfigInterface + */ + private $scopeConfig; + + /** + * Core registry + * + * @var Registry + */ + private $coreRegistry; + + /** + * @param ScopeConfigInterface $scopeConfig + * @param Registry $registry + */ + public function __construct( + ScopeConfigInterface $scopeConfig, + Registry $registry + ) { + $this->scopeConfig = $scopeConfig; + $this->coreRegistry = $registry; + } + + /** + * Return logo image path + * + * @return string|null + */ + public function getPath(): ?string + { + $path = null; + $storeId = null; + $order = $this->coreRegistry->registry('current_order'); + if ($order instanceof Order) { + $storeId = $order->getStoreId(); + } + $storeLogoPath = $this->scopeConfig->getValue( + 'sales/identity/logo_html', + ScopeInterface::SCOPE_STORE, + $storeId + ); + if ($storeLogoPath !== null) { + $path = 'sales/store/logo_html/' . $storeLogoPath; + } + return $path; + } +} diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml index 4410a6fc4a9a2..8a52e65a9f70c 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml @@ -44,5 +44,10 @@ <block class="Magento\Sales\Block\Order\Info" as="sales.order.print.info" name="sales.order.print.info" template="Magento_Sales::order/info.phtml"/> </referenceContainer> <block class="Magento\Framework\View\Element\Template" name="additional.product.info" template="Magento_Theme::template.phtml"/> + <referenceBlock name="logo"> + <arguments> + <argument name="logoPathResolver" xsi:type="object">Magento\Sales\ViewModel\Header\LogoPathResolver</argument> + </arguments> + </referenceBlock> </body> </page> diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_printcreditmemo.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_printcreditmemo.xml index 0021eeede4f2b..317ee419f6d96 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_printcreditmemo.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_printcreditmemo.xml @@ -28,5 +28,10 @@ </block> </referenceContainer> <block class="Magento\Framework\View\Element\Template" name="additional.product.info" template="Magento_Theme::template.phtml"/> + <referenceBlock name="logo"> + <arguments> + <argument name="logoPathResolver" xsi:type="object">Magento\Sales\ViewModel\Header\LogoPathResolver</argument> + </arguments> + </referenceBlock> </body> </page> diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_printinvoice.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_printinvoice.xml index 0272286696e24..e0bb15bc0e7fd 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_printinvoice.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_printinvoice.xml @@ -35,5 +35,10 @@ </block> </referenceContainer> <block class="Magento\Framework\View\Element\Template" name="additional.product.info" template="Magento_Theme::template.phtml"/> + <referenceBlock name="logo"> + <arguments> + <argument name="logoPathResolver" xsi:type="object">Magento\Sales\ViewModel\Header\LogoPathResolver</argument> + </arguments> + </referenceBlock> </body> </page> diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_printshipment.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_printshipment.xml index 30053b41a96a9..b7940c0d406cc 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_order_printshipment.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_printshipment.xml @@ -20,5 +20,10 @@ </block> </referenceContainer> <block class="Magento\Framework\View\Element\Template" name="additional.product.info" template="Magento_Theme::template.phtml"/> + <referenceBlock name="logo"> + <arguments> + <argument name="logoPathResolver" xsi:type="object">Magento\Sales\ViewModel\Header\LogoPathResolver</argument> + </arguments> + </referenceBlock> </body> </page> diff --git a/app/code/Magento/Theme/Block/Html/Header/Logo.php b/app/code/Magento/Theme/Block/Html/Header/Logo.php index 792ee95de4995..3c43e5bfc6fe1 100644 --- a/app/code/Magento/Theme/Block/Html/Header/Logo.php +++ b/app/code/Magento/Theme/Block/Html/Header/Logo.php @@ -6,6 +6,8 @@ namespace Magento\Theme\Block\Html\Header; +use Magento\Theme\ViewModel\Block\Html\Header\LogoPathResolverInterface; + /** * Logo page header block * @@ -124,16 +126,16 @@ public function getLogoHeight() */ protected function _getLogoUrl() { - $folderName = \Magento\Config\Model\Config\Backend\Image\Logo::UPLOAD_DIR; - $storeLogoPath = $this->_scopeConfig->getValue( - 'design/header/logo_src', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE - ); - $path = $folderName . '/' . $storeLogoPath; + $path = null; + /** @var LogoPathResolverInterface $logoPathResolver */ + $logoPathResolver = $this->getData('logoPathResolver'); + if ($logoPathResolver instanceof LogoPathResolverInterface) { + $path = $logoPathResolver->getPath(); + } $logoUrl = $this->_urlBuilder ->getBaseUrl(['_type' => \Magento\Framework\UrlInterface::URL_TYPE_MEDIA]) . $path; - if ($storeLogoPath !== null && $this->_isFile($path)) { + if ($path !== null && $this->_isFile($path)) { $url = $logoUrl; } elseif ($this->getLogoFile()) { $url = $this->getViewFileUrl($this->getLogoFile()); diff --git a/app/code/Magento/Theme/Test/Unit/Block/Html/Header/LogoTest.php b/app/code/Magento/Theme/Test/Unit/Block/Html/Header/LogoTest.php index 1978362810763..a5095674a4673 100644 --- a/app/code/Magento/Theme/Test/Unit/Block/Html/Header/LogoTest.php +++ b/app/code/Magento/Theme/Test/Unit/Block/Html/Header/LogoTest.php @@ -7,6 +7,7 @@ namespace Magento\Theme\Test\Unit\Block\Html\Header; +use Magento\Theme\ViewModel\Block\Html\Header\LogoPathResolverInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\Read; @@ -25,11 +26,11 @@ public function testGetLogoSrc() { $filesystem = $this->createMock(Filesystem::class); $mediaDirectory = $this->createMock(Read::class); - $scopeConfig = $this->getMockForAbstractClass(ScopeConfigInterface::class); + $logoPathResolver = $this->getMockForAbstractClass(LogoPathResolverInterface::class); $urlBuilder = $this->getMockForAbstractClass(UrlInterface::class); - $scopeConfig->expects($this->once())->method('getValue')->willReturn('default/image.gif'); + $logoPathResolver->expects($this->once())->method('getPath')->willReturn('logo/default/image.gif'); $urlBuilder->expects( $this->once() )->method( @@ -46,7 +47,7 @@ public function testGetLogoSrc() $objectManager = new ObjectManager($this); $arguments = [ - 'scopeConfig' => $scopeConfig, + 'data' => ['logoPathResolver' => $logoPathResolver], 'urlBuilder' => $urlBuilder, 'fileStorageHelper' => $helper, 'filesystem' => $filesystem, diff --git a/app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolver.php b/app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolver.php new file mode 100644 index 0000000000000..1a10fe9177320 --- /dev/null +++ b/app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolver.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Theme\ViewModel\Block\Html\Header; + +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Config\Model\Config\Backend\Image\Logo; +use Magento\Store\Model\ScopeInterface; +use Magento\Framework\View\Element\Block\ArgumentInterface; + +/** + * Class for resolving logo path + */ +class LogoPathResolver implements LogoPathResolverInterface, ArgumentInterface +{ + /** + * @var ScopeConfigInterface + */ + private $scopeConfig; + + /** + * @param ScopeConfigInterface $scopeConfig + */ + public function __construct( + ScopeConfigInterface $scopeConfig + ) { + $this->scopeConfig = $scopeConfig; + } + + /** + * Return logo image path + * + * @return string|null + */ + public function getPath(): ?string + { + $path = null; + $storeLogoPath = $this->scopeConfig->getValue( + 'design/header/logo_src', + ScopeInterface::SCOPE_STORE + ); + if ($storeLogoPath !== null) { + $path = Logo::UPLOAD_DIR . '/' . $storeLogoPath; + } + return $path; + } +} diff --git a/app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolverInterface.php b/app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolverInterface.php new file mode 100644 index 0000000000000..3ac8442aa0ea7 --- /dev/null +++ b/app/code/Magento/Theme/ViewModel/Block/Html/Header/LogoPathResolverInterface.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Theme\ViewModel\Block\Html\Header; + +/** + * Interface for resolving logo path + */ +interface LogoPathResolverInterface +{ + /** + * Return logo image path + * + * @return null|string + */ + public function getPath(): ?string; +} diff --git a/app/code/Magento/Theme/view/frontend/layout/default.xml b/app/code/Magento/Theme/view/frontend/layout/default.xml index bf76933b356c0..f3e57b12150c9 100644 --- a/app/code/Magento/Theme/view/frontend/layout/default.xml +++ b/app/code/Magento/Theme/view/frontend/layout/default.xml @@ -51,7 +51,11 @@ </container> </container> <container name="header-wrapper" label="Page Header" as="header-wrapper" htmlTag="div" htmlClass="header content"> - <block class="Magento\Theme\Block\Html\Header\Logo" name="logo"/> + <block class="Magento\Theme\Block\Html\Header\Logo" name="logo"> + <arguments> + <argument name="logoPathResolver" xsi:type="object">Magento\Theme\ViewModel\Block\Html\Header\LogoPathResolver</argument> + </arguments> + </block> </container> </referenceContainer> <referenceContainer name="page.top"> diff --git a/dev/tests/integration/testsuite/Magento/Sales/Block/Order/PrintOrder/LogoTest.php b/dev/tests/integration/testsuite/Magento/Sales/Block/Order/PrintOrder/LogoTest.php new file mode 100644 index 0000000000000..aadd3ab7b956e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/Block/Order/PrintOrder/LogoTest.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Sales\Block\Order\PrintOrder; + +use Magento\Framework\View\LayoutInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\App\State; +use Magento\Theme\Block\Html\Header\Logo; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\ObjectManagerInterface; +use Magento\Theme\ViewModel\Block\Html\Header\LogoPathResolver as LogoPathResolverDefault; +use Magento\Sales\ViewModel\Header\LogoPathResolver as LogoPathResolverSales; +use \PHPUnit\Framework\TestCase; + +class LogoTest extends TestCase +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var WriteInterface + */ + private $mediaDirectory; + + protected function setUp(): void + { + $this->objectManager = Bootstrap::getObjectManager(); + $filesystem = $this->objectManager->get(Filesystem::class); + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->objectManager->get(State::class) + ->setAreaCode(\Magento\Framework\App\Area::AREA_FRONTEND); + Bootstrap::getInstance() + ->loadArea(\Magento\Framework\App\Area::AREA_FRONTEND); + } + + /** + * @magentoConfigFixture default_store design/header/logo_src default/logo.jpg + * @magentoConfigFixture default_store sales/identity/logo_html default/logo_sales.jpg + * @throws \Magento\Framework\Exception\FileSystemException + */ + public function testGetLogoSrc(): void + { + $host = 'http://localhost/media/'; + $defaultLogoFile= 'logo.jpg'; + $defaultPath = 'logo/default/' . $defaultLogoFile; + $salesLogoFile = 'logo_sales.jpg'; + $salesPath = 'sales/store/logo_html/default/' . $salesLogoFile; + $this->mediaDirectory->writeFile($defaultPath, ''); + $this->mediaDirectory->writeFile($salesPath, ''); + $blockArguments = ['data' => + ['logoPathResolver' => $this->objectManager->get(LogoPathResolverDefault::class)] + ]; + /** @var Logo $block */ + $block = $this->objectManager->create(LayoutInterface::class) + ->createBlock(Logo::class, 'logo', $blockArguments); + $this->assertSame($host . $defaultPath, $block->getLogoSrc()); + $blockArguments = ['data' => + ['logoPathResolver' => $this->objectManager->get(LogoPathResolverSales::class)] + ]; + /** @var Logo $block */ + $block = $this->objectManager->create(LayoutInterface::class) + ->createBlock(Logo::class, 'logo', $blockArguments); + $this->assertSame($host . $salesPath, $block->getLogoSrc()); + $this->mediaDirectory->delete($defaultPath); + $this->mediaDirectory->delete($salesPath); + } +} From a1808865c58768cc5e9afdb3c301893743ec6bfd Mon Sep 17 00:00:00 2001 From: Elisei <brunoelisei@gmail.com> Date: Wed, 16 Dec 2020 11:01:53 -0300 Subject: [PATCH 272/346] Fixed #31211 --- app/code/Magento/Vault/i18n/en_US.csv | 2 +- .../view/frontend/templates/customer_account/credit_card.phtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Vault/i18n/en_US.csv b/app/code/Magento/Vault/i18n/en_US.csv index 0c54d583198d1..6030e83193a8a 100644 --- a/app/code/Magento/Vault/i18n/en_US.csv +++ b/app/code/Magento/Vault/i18n/en_US.csv @@ -13,4 +13,4 @@ Actions,Actions Delete,Delete "PayPal Account","PayPal Account" Cancel,Cancel -"Are you sure you want to delete this card: %1?","Are you sure you want to delete this card: %1?" \ No newline at end of file +"Are you sure you want to delete this card: %1?","Are you sure you want to delete this card: %1?" diff --git a/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml b/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml index a2439898799cd..c61ac41329548 100644 --- a/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml +++ b/app/code/Magento/Vault/view/frontend/templates/customer_account/credit_card.phtml @@ -43,7 +43,7 @@ $ccNumberView = $block->escapeHtml($block->getNumberLast4Digits()); "modalClass": "my-credit-cards-popup", "toggleEvent": "click", "title": "<?= $block->escapeHtml(__('Delete')) ?>", - "content": "<?= $block->escapeHtml(__('Are you sure you want to delete this card: %1?', /* @noEscape */ $ccNumberView)) ?>" + "content": "<?= $block->escapeHtml(__('Are you sure you want to delete this card: %1?', $ccNumberView)) ?>" } }'> <span><?= $block->escapeHtml(__('Delete')) ?></span> From 92ecbbfeabd9edd0b137915f61bbacfa123a7e8e Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 16 Dec 2020 17:21:05 +0200 Subject: [PATCH 273/346] MC-39765: No such entity with addressId, occurs randomly on visitors browser. System Log Generated --- .../Magento/Persistent/Observer/EmulateCustomerObserver.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php index c991836a287d2..1ff81137de57b 100644 --- a/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php +++ b/app/code/Magento/Persistent/Observer/EmulateCustomerObserver.php @@ -87,7 +87,7 @@ public function execute(\Magento\Framework\Event\Observer $observer) /** @var \Magento\Customer\Api\Data\CustomerInterface $customer */ $customer = $this->customerRepository->getById($this->_persistentSession->getSession()->getCustomerId()); if ($defaultShipping = $customer->getDefaultShipping()) { - $address = $this->getCustomerAddressById($defaultShipping); + $address = $this->getCustomerAddressById((int) $defaultShipping); if ($address !== null) { $this->_customerSession->setDefaultTaxShippingAddress( @@ -103,7 +103,7 @@ public function execute(\Magento\Framework\Event\Observer $observer) } if ($defaultBilling = $customer->getDefaultBilling()) { - $address = $this->getCustomerAddressById($defaultBilling); + $address = $this->getCustomerAddressById((int) $defaultBilling); if ($address !== null) { $this->_customerSession->setDefaultTaxBillingAddress([ @@ -127,7 +127,7 @@ public function execute(\Magento\Framework\Event\Observer $observer) * @param int $addressId * @return \Magento\Customer\Api\Data\AddressInterface|null */ - private function getCustomerAddressById($addressId) + private function getCustomerAddressById(int $addressId) { try { return $this->addressRepository->getById($addressId); From e55a9e3624bb7b7e2d0a35877dcc1a97975962e7 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Wed, 16 Dec 2020 18:06:20 +0200 Subject: [PATCH 274/346] MC-39104: 2 error messages in Cart when product is out of stock --- .../QuantityValidator/Initializer/QuantityValidatorTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php index 0a1eee76d6960..36b9fd0adeb81 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/QuantityValidatorTest.php @@ -490,12 +490,11 @@ public function testValidateOutStockWithAlreadyErrorInQuoteItem(): void $this->stockStatusMock->expects($this->atLeastOnce()) ->method('getStockStatus') ->willReturn(1); - $this->quoteItemMock->expects($this->never()) + $this->quoteItemMock->expects($this->once()) ->method('addErrorInfo') ->with( - 'cataloginventory', + null, Data::ERROR_QTY, - __('This product is out of stock.') ); $this->quoteMock->expects($this->once()) ->method('addErrorInfo') From 253f0d2e9507f05ccb2fd00f0ba2f4d79c0ad5e4 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 16 Dec 2020 12:49:20 -0600 Subject: [PATCH 275/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- app/code/Magento/UrlRewrite/Model/UrlRewrite.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index 3722c27a1b312..1fa3ef049daae 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -142,7 +142,8 @@ public function setMetadata($metadata) * @param int $storeId * @return UrlRewrite|null */ - private function getFinalTargetUrlRewrite(string $path, int $storeId) { + private function getFinalTargetUrlRewrite(string $path, int $storeId): ?UrlRewrite + { $urlRewriteTarget = $this->urlFinder->findOneByData( [ 'request_path' => $path, @@ -165,7 +166,8 @@ private function getFinalTargetUrlRewrite(string $path, int $storeId) { /** * Clean the cache for entities affected by current rewrite */ - private function cleanEntitiesCache() { + private function cleanEntitiesCache() + { if ($this->getEntityType() === Rewrite::ENTITY_TYPE_CUSTOM) { $urlRewrite = $this->getFinalTargetUrlRewrite( $this->getTargetPath(), From a1750ac2296bac2f728a5462ce696df70e1988df Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 16 Dec 2020 15:57:42 -0600 Subject: [PATCH 276/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../Magento/UrlRewrite/Model/UrlRewrite.php | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index 1fa3ef049daae..5f867e6ef0aa6 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -168,28 +168,30 @@ private function getFinalTargetUrlRewrite(string $path, int $storeId): ?UrlRewri */ private function cleanEntitiesCache() { - if ($this->getEntityType() === Rewrite::ENTITY_TYPE_CUSTOM) { - $urlRewrite = $this->getFinalTargetUrlRewrite( - $this->getTargetPath(), - (int)$this->getStoreId() - ); + if (!$this->isEmpty()) { + if ($this->getEntityType() === Rewrite::ENTITY_TYPE_CUSTOM) { + $urlRewrite = $this->getFinalTargetUrlRewrite( + $this->getTargetPath(), + (int)$this->getStoreId() + ); - if ($urlRewrite) { - $this->cleanCacheForEntity($urlRewrite->getEntityType(), (int) $urlRewrite->getEntityId()); - } + if ($urlRewrite) { + $this->cleanCacheForEntity($urlRewrite->getEntityType(), (int) $urlRewrite->getEntityId()); + } - if ($this->getOrigData() && $this->getOrigData('target_path') !== $this->getTargetPath()) { - $origUrlRewrite = $this->getFinalTargetUrlRewrite( - $this->getOrigData('target_path'), - (int)$this->getOrigData('store_id') - ); + if ($this->getOrigData() && $this->getOrigData('target_path') !== $this->getTargetPath()) { + $origUrlRewrite = $this->getFinalTargetUrlRewrite( + $this->getOrigData('target_path'), + (int)$this->getOrigData('store_id') + ); - if ($origUrlRewrite) { - $this->cleanCacheForEntity($origUrlRewrite->getEntityType(), (int) $origUrlRewrite->getEntityId()); + if ($origUrlRewrite) { + $this->cleanCacheForEntity($origUrlRewrite->getEntityType(), (int) $origUrlRewrite->getEntityId()); + } } + } else { + $this->cleanCacheForEntity($this->getEntityType(), (int) $this->getEntityId()); } - } else { - $this->cleanCacheForEntity($this->getEntityType(), (int) $this->getEntityId()); } } From 3ce3b50dcb755a12a512f5df011f6754cb5d1acb Mon Sep 17 00:00:00 2001 From: ruslankostiv <rkostiv@adobe.com> Date: Wed, 16 Dec 2020 16:47:51 -0600 Subject: [PATCH 277/346] SFAPP-188: ComposetTest fails on blacklisted modules --- .../testsuite/Magento/Test/Integrity/ComposerTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php index 1c0f451de71dc..f57a29e9bda0d 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php @@ -266,8 +266,10 @@ private function assertAutoloadRegistrar(\StdClass $json, $dir) */ private function assertNoVersionSpecified(\StdClass $json) { - $errorMessage = 'Version must not be specified in the root and package composer JSON files in Git'; - $this->assertObjectNotHasAttribute('version', $json, $errorMessage); + if (!in_array($json->name, self::$rootComposerModuleBlacklist)) { + $errorMessage = 'Version must not be specified in the root and package composer JSON files in Git'; + $this->assertObjectNotHasAttribute('version', $json, $errorMessage); + } } /** From 375fd4cb19c05cdbb88a047865ed0d23bf310e21 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Wed, 16 Dec 2020 17:11:47 -0600 Subject: [PATCH 278/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- app/code/Magento/UrlRewrite/Model/UrlRewrite.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index 5f867e6ef0aa6..d82781ee66450 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -18,6 +18,7 @@ use Magento\Framework\Serialize\Serializer\Json; use Magento\UrlRewrite\Controller\Adminhtml\Url\Rewrite; use Magento\UrlRewrite\Model\ResourceModel\UrlRewriteCollection; +use Magento\UrlRewrite\Service\V1\Data\UrlRewrite as UrlRewriteService; /** * UrlRewrite model class @@ -140,9 +141,9 @@ public function setMetadata($metadata) * * @param string $path * @param int $storeId - * @return UrlRewrite|null + * @return UrlRewriteService|null */ - private function getFinalTargetUrlRewrite(string $path, int $storeId): ?UrlRewrite + private function getFinalTargetUrlRewrite(string $path, int $storeId): ?UrlRewriteService { $urlRewriteTarget = $this->urlFinder->findOneByData( [ @@ -166,7 +167,7 @@ private function getFinalTargetUrlRewrite(string $path, int $storeId): ?UrlRewri /** * Clean the cache for entities affected by current rewrite */ - private function cleanEntitiesCache() + public function cleanEntitiesCache() { if (!$this->isEmpty()) { if ($this->getEntityType() === Rewrite::ENTITY_TYPE_CUSTOM) { @@ -215,7 +216,7 @@ private function cleanCacheForEntity(string $entityType, int $entityId) */ public function afterDelete() { - $this->cleanEntitiesCache(); + $this->_getResource()->addCommitCallback([$this, 'cleanEntitiesCache']); return parent::afterDelete(); } @@ -224,7 +225,7 @@ public function afterDelete() */ public function afterSave() { - $this->cleanEntitiesCache(); + $this->_getResource()->addCommitCallback([$this, 'cleanEntitiesCache']); return parent::afterSave(); } } From b7fe543acf0f5e3bbe0a8ba65b3a93cbfba28cd2 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Thu, 17 Dec 2020 11:26:31 +0200 Subject: [PATCH 279/346] refactored --- .../AdminSelectAttributeSetOnEditProductPageActionGroup.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml index 42f7f72c1cd73..c1d1d3dee1123 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml @@ -10,8 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminSelectAttributeSetOnEditProductPageActionGroup"> <annotations> - <description>Selects the specified value from the Attribute Set dropdown. - The Edit Product Page should be opened prior to Action Group execution</description> + <description>Selects the specified value from the Attribute Set dropdown.</description> </annotations> <arguments> <argument name="attributeSet" type="string"/> From d063cd634be1fecd8d13de27f15e1afcb78e9a5d Mon Sep 17 00:00:00 2001 From: Anna Pak <58164147+AnnaAPak@users.noreply.github.com> Date: Thu, 17 Dec 2020 11:35:16 +0200 Subject: [PATCH 280/346] Update app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml Co-authored-by: Eduard Chitoraga <e.chitoraga@atwix.com> --- .../AdminSelectAttributeSetOnEditProductPageActionGroup.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml index 9b3f44516dadc..5624d3a1001c1 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml @@ -13,8 +13,7 @@ <<<<<<< HEAD <description>Selects the specified value from the Attribute Set dropdown.</description> ======= - <description>Selects the specified value from the Attribute Set dropdown. - The Edit Product Page should be opened prior to Action Group execution</description> + <description>Selects the specified value from the Attribute Set dropdown on the opened product edit page.</description> >>>>>>> 88b58a08d39906584398e0c7762413e18c054a27 </annotations> <arguments> From 941349a80659143e7501a5d65b68a9bc79f6738c Mon Sep 17 00:00:00 2001 From: Anna Pak <58164147+AnnaAPak@users.noreply.github.com> Date: Thu, 17 Dec 2020 11:36:11 +0200 Subject: [PATCH 281/346] refactored --- .../AdminSelectAttributeSetOnEditProductPageActionGroup.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml index 5624d3a1001c1..31a4521331664 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminSelectAttributeSetOnEditProductPageActionGroup.xml @@ -10,11 +10,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AdminSelectAttributeSetOnEditProductPageActionGroup"> <annotations> -<<<<<<< HEAD - <description>Selects the specified value from the Attribute Set dropdown.</description> -======= <description>Selects the specified value from the Attribute Set dropdown on the opened product edit page.</description> ->>>>>>> 88b58a08d39906584398e0c7762413e18c054a27 </annotations> <arguments> <argument name="attributeSet" type="string"/> From 7f9a7fd39b4514fee0ca9eb0a1a8701c6f2b4030 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Thu, 17 Dec 2020 15:28:31 +0200 Subject: [PATCH 282/346] MC-39864: [Magento Cloud] - Tax Miscalculation --- .../Model/Order/Creditmemo/Total/Tax.php | 209 ++++++++++++------ .../Model/Order/Creditmemo/Total/TaxTest.php | 32 +-- 2 files changed, 156 insertions(+), 85 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index 95dace13d832f..9e6e8979e46ee 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -5,22 +5,20 @@ */ namespace Magento\Sales\Model\Order\Creditmemo\Total; +use Magento\Sales\Model\Order\Creditmemo; + /** * Collects credit memo taxes. */ class Tax extends AbstractTotal { /** - * Collects credit memo taxes. - * - * @param \Magento\Sales\Model\Order\Creditmemo $creditmemo - * @return $this - * + * {@inheritdoc} * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) + public function collect(Creditmemo $creditmemo) { $shippingTaxAmount = 0; $baseShippingTaxAmount = 0; @@ -28,38 +26,37 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $baseTotalTax = 0; $totalDiscountTaxCompensation = 0; $baseTotalDiscountTaxCompensation = 0; - $order = $creditmemo->getOrder(); - /** @var $item \Magento\Sales\Model\Order\Creditmemo\Item */ foreach ($creditmemo->getAllItems() as $item) { $orderItem = $item->getOrderItem(); if ($orderItem->isDummy() || $item->getQty() <= 0) { continue; } + $orderItemTax = (double)$orderItem->getTaxInvoiced(); $baseOrderItemTax = (double)$orderItem->getBaseTaxInvoiced(); $orderItemQty = (double)$orderItem->getQtyInvoiced(); if ($orderItemQty) { - /** - * Check item tax amount - */ - - $tax = $orderItemTax - $orderItem->getTaxRefunded(); - $baseTax = $baseOrderItemTax - $orderItem->getBaseTaxRefunded(); - $discountTaxCompensation = $orderItem->getDiscountTaxCompensationInvoiced() - - $orderItem->getDiscountTaxCompensationRefunded(); - $baseDiscountTaxCompensation = $orderItem->getBaseDiscountTaxCompensationInvoiced() - - $orderItem->getBaseDiscountTaxCompensationRefunded(); + /** Check item tax amount */ + $tax = ($orderItemTax - $orderItem->getTaxRefunded()); + $baseTax = ($baseOrderItemTax - $orderItem->getBaseTaxRefunded()); + $discountTaxCompensation = ($orderItem->getDiscountTaxCompensationInvoiced() + - $orderItem->getDiscountTaxCompensationRefunded()); + $baseDiscountTaxCompensation = ($orderItem->getBaseDiscountTaxCompensationInvoiced() + - $orderItem->getBaseDiscountTaxCompensationRefunded()); if (!$item->isLast()) { - $availableQty = $orderItemQty - $orderItem->getQtyRefunded(); + $availableQty = ($orderItemQty - $orderItem->getQtyRefunded()); $tax = $creditmemo->roundPrice($tax / $availableQty * $item->getQty()); - $baseTax = $creditmemo->roundPrice($baseTax / $availableQty * $item->getQty(), 'base'); - $discountTaxCompensation = - $creditmemo->roundPrice($discountTaxCompensation / $availableQty * $item->getQty()); - $baseDiscountTaxCompensation = - $creditmemo->roundPrice($baseDiscountTaxCompensation / $availableQty * $item->getQty(), 'base'); + $baseTax = $creditmemo->roundPrice(($baseTax / $availableQty * $item->getQty()), 'base'); + $discountTaxCompensation = $creditmemo->roundPrice( + $discountTaxCompensation / $availableQty * $item->getQty() + ); + $baseDiscountTaxCompensation = $creditmemo->roundPrice( + $baseDiscountTaxCompensation / $availableQty * $item->getQty(), + 'base' + ); } $item->setTaxAmount($tax); @@ -77,14 +74,14 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $isPartialShippingRefunded = false; $baseOrderShippingAmount = (float)$order->getBaseShippingAmount(); if ($invoice = $creditmemo->getInvoice()) { - //recalculate tax amounts in case if refund shipping value was changed + // recalculate tax amounts in case if refund shipping value was changed if ($baseOrderShippingAmount && $creditmemo->getBaseShippingAmount() !== null) { - $taxFactor = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount; - $shippingTaxAmount = $invoice->getShippingTaxAmount() * $taxFactor; - $baseShippingTaxAmount = $invoice->getBaseShippingTaxAmount() * $taxFactor; - $totalDiscountTaxCompensation += $invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor; - $baseTotalDiscountTaxCompensation += - $invoice->getBaseShippingDiscountTaxCompensationAmnt() * $taxFactor; + $taxFactor = ($creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount); + $shippingTaxAmount = ($invoice->getShippingTaxAmount() * $taxFactor); + $baseShippingTaxAmount = ($invoice->getBaseShippingTaxAmount() * $taxFactor); + $totalDiscountTaxCompensation += ($invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor); + $baseTotalDiscountTaxCompensation += $invoice->getBaseShippingDiscountTaxCompensationAmnt() + * $taxFactor; $shippingTaxAmount = $creditmemo->roundPrice($shippingTaxAmount); $baseShippingTaxAmount = $creditmemo->roundPrice($baseShippingTaxAmount, 'base'); $totalDiscountTaxCompensation = $creditmemo->roundPrice($totalDiscountTaxCompensation); @@ -97,61 +94,52 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) } } else { $orderShippingAmount = $order->getShippingAmount(); - $baseOrderShippingRefundedAmount = $order->getBaseShippingRefunded(); - $shippingTaxAmount = 0; $baseShippingTaxAmount = 0; $shippingDiscountTaxCompensationAmount = 0; $baseShippingDiscountTaxCompensationAmount = 0; - - $shippingDelta = $baseOrderShippingAmount - $baseOrderShippingRefundedAmount; + $shippingDelta = ($baseOrderShippingAmount - $baseOrderShippingRefundedAmount); if ($shippingDelta > $creditmemo->getBaseShippingAmount()) { - $part = $creditmemo->getShippingAmount() / $orderShippingAmount; - $basePart = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount; - $shippingTaxAmount = $order->getShippingTaxAmount() * $part; - $baseShippingTaxAmount = $order->getBaseShippingTaxAmount() * $basePart; + $part = ($creditmemo->getShippingAmount() / $orderShippingAmount); + $basePart = ($creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount); + $shippingTaxAmount = ($order->getShippingTaxAmount() * $part); + $baseShippingTaxAmount = ($order->getBaseShippingTaxAmount() * $basePart); $shippingDiscountTaxCompensationAmount = $order->getShippingDiscountTaxCompensationAmount() * $part; - $baseShippingDiscountTaxCompensationAmount = - $order->getBaseShippingDiscountTaxCompensationAmnt() * $basePart; + $baseShippingDiscountTaxCompensationAmount = $order->getBaseShippingDiscountTaxCompensationAmnt() + * $basePart; $shippingTaxAmount = $creditmemo->roundPrice($shippingTaxAmount); $baseShippingTaxAmount = $creditmemo->roundPrice($baseShippingTaxAmount, 'base'); - $shippingDiscountTaxCompensationAmount = - $creditmemo->roundPrice($shippingDiscountTaxCompensationAmount); - $baseShippingDiscountTaxCompensationAmount = - $creditmemo->roundPrice($baseShippingDiscountTaxCompensationAmount, 'base'); + $shippingDiscountTaxCompensationAmount = $creditmemo->roundPrice( + $shippingDiscountTaxCompensationAmount + ); + $baseShippingDiscountTaxCompensationAmount = $creditmemo->roundPrice( + $baseShippingDiscountTaxCompensationAmount, + 'base' + ); if ($part < 1 && $order->getShippingTaxAmount() > 0) { $isPartialShippingRefunded = true; } } elseif ($shippingDelta == $creditmemo->getBaseShippingAmount()) { $shippingTaxAmount = $order->getShippingTaxAmount() - $order->getShippingTaxRefunded(); $baseShippingTaxAmount = $order->getBaseShippingTaxAmount() - $order->getBaseShippingTaxRefunded(); - $shippingDiscountTaxCompensationAmount = $order->getShippingDiscountTaxCompensationAmount() - - $order->getShippingDiscountTaxCompensationRefunded(); - $baseShippingDiscountTaxCompensationAmount = $order->getBaseShippingDiscountTaxCompensationAmnt() - - $order->getBaseShippingDiscountTaxCompensationRefunded(); + $shippingDiscountTaxCompensationAmount = $order->getShippingDiscountTaxCompensationAmount() + - $order->getShippingDiscountTaxCompensationRefunded(); + $baseShippingDiscountTaxCompensationAmount = $order->getBaseShippingDiscountTaxCompensationAmnt() + - $order->getBaseShippingDiscountTaxCompensationRefunded(); } + $totalTax += $shippingTaxAmount; $baseTotalTax += $baseShippingTaxAmount; $totalDiscountTaxCompensation += $shippingDiscountTaxCompensationAmount; $baseTotalDiscountTaxCompensation += $baseShippingDiscountTaxCompensationAmount; } - $allowedTax = $order->getTaxInvoiced() - $order->getTaxRefunded() - $creditmemo->getTaxAmount(); - $allowedBaseTax = $order->getBaseTaxInvoiced() - $order->getBaseTaxRefunded() - $creditmemo->getBaseTaxAmount(); - $allowedDiscountTaxCompensation = $order->getDiscountTaxCompensationInvoiced() + - $order->getShippingDiscountTaxCompensationAmount() - - $order->getDiscountTaxCompensationRefunded() - - $order->getShippingDiscountTaxCompensationRefunded() - - $creditmemo->getDiscountTaxCompensationAmount() - - $creditmemo->getShippingDiscountTaxCompensationAmount(); - $allowedBaseDiscountTaxCompensation = $order->getBaseDiscountTaxCompensationInvoiced() + - $order->getBaseShippingDiscountTaxCompensationAmnt() - - $order->getBaseDiscountTaxCompensationRefunded() - - $order->getBaseShippingDiscountTaxCompensationRefunded() - - $creditmemo->getBaseShippingDiscountTaxCompensationAmnt() - - $creditmemo->getBaseDiscountTaxCompensationAmount(); + $allowedTax = $this->calculateAllowedTax($creditmemo); + $allowedBaseTax = $this->calculateAllowedBaseTax($creditmemo); + $allowedDiscountTaxCompensation = $this->calculateAllowedDiscountTaxCompensation($creditmemo); + $allowedBaseDiscountTaxCompensation = $this->calculateAllowedBaseDiscountTaxCompensation($creditmemo); if ($creditmemo->isLast() && !$isPartialShippingRefunded) { $totalTax = $allowedTax; @@ -161,10 +149,11 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) } else { $totalTax = min($allowedTax, $totalTax); $baseTotalTax = min($allowedBaseTax, $baseTotalTax); - $totalDiscountTaxCompensation = - min($allowedDiscountTaxCompensation, $totalDiscountTaxCompensation); - $baseTotalDiscountTaxCompensation = - min($allowedBaseDiscountTaxCompensation, $baseTotalDiscountTaxCompensation); + $totalDiscountTaxCompensation = min($allowedDiscountTaxCompensation, $totalDiscountTaxCompensation); + $baseTotalDiscountTaxCompensation = min( + $allowedBaseDiscountTaxCompensation, + $baseTotalDiscountTaxCompensation + ); } $creditmemo->setTaxAmount($creditmemo->getTaxAmount() + $totalTax); @@ -177,9 +166,91 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $creditmemo->setGrandTotal($creditmemo->getGrandTotal() + $totalTax + $totalDiscountTaxCompensation); $creditmemo->setBaseGrandTotal( - $creditmemo->getBaseGrandTotal() + - $baseTotalTax + $baseTotalDiscountTaxCompensation + $creditmemo->getBaseGrandTotal() + $baseTotalTax + $baseTotalDiscountTaxCompensation ); return $this; + + } + + /** + * Calculate allowed to Credit Memo tax amount + * + * @param Creditmemo $creditMemo + * @return float + */ + private function calculateAllowedTax(Creditmemo $creditMemo): float + { + $invoice = $creditMemo->getInvoice(); + $order = $creditMemo->getOrder(); + $amount = $invoice !== null ? $invoice->getTaxAmount() : $order->getTaxInvoiced(); + + return (float) $amount - $order->getTaxRefunded() - $creditMemo->getTaxAmount(); + } + + /** + * Calculate allowed to Credit Memo tax amount in the base currency + * + * @param Creditmemo $creditMemo + * @return float + */ + private function calculateAllowedBaseTax(Creditmemo $creditMemo): float + { + $invoice = $creditMemo->getInvoice(); + $order = $creditMemo->getOrder(); + $amount = $invoice !== null ? $invoice->getBaseTaxAmount() : $order->getBaseTaxInvoiced(); + + return (float) $amount - $order->getBaseTaxRefunded() - $creditMemo->getBaseTaxAmount(); + } + + /** + * Calculate allowed to Credit Memo discount tax compensation amount + * + * @param Creditmemo $creditMemo + * @return float + */ + private function calculateAllowedDiscountTaxCompensation(Creditmemo $creditMemo): float + { + $invoice = $creditMemo->getInvoice(); + $order = $creditMemo->getOrder(); + + if ($invoice) { + $amount = $invoice->getDiscountTaxCompensationAmount() + + $invoice->getShippingDiscountTaxCompensationAmount(); + } else { + $amount = $order->getDiscountTaxCompensationInvoiced() + + $order->getShippingDiscountTaxCompensationAmount(); + } + + return (float) $amount + - $order->getDiscountTaxCompensationRefunded() + - $order->getShippingDiscountTaxCompensationRefunded() + - $creditMemo->getDiscountTaxCompensationAmount() + - $creditMemo->getShippingDiscountTaxCompensationAmount(); + } + + /** + * Calculate allowed to Credit Memo discount tax compensation amount in the base currency + * + * @param Creditmemo $creditMemo + * @return float + */ + private function calculateAllowedBaseDiscountTaxCompensation(Creditmemo $creditMemo): float + { + $invoice = $creditMemo->getInvoice(); + $order = $creditMemo->getOrder(); + + if ($invoice) { + $amount = $invoice->getBaseDiscountTaxCompensationAmount() + + $invoice->getBaseShippingDiscountTaxCompensationAmnt(); + } else { + $amount = $order->getBaseDiscountTaxCompensationInvoiced() + + $order->getBaseShippingDiscountTaxCompensationAmnt(); + } + + return (float) $amount + - $order->getBaseDiscountTaxCompensationRefunded() + - $order->getBaseShippingDiscountTaxCompensationRefunded() + - $creditMemo->getBaseShippingDiscountTaxCompensationAmnt() + - $creditMemo->getBaseDiscountTaxCompensationAmount(); } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php index 94346fc1b7a28..7c9d249124a9a 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php @@ -17,6 +17,9 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +/** + * Class to test Collecting credit memo taxes + */ class TaxTest extends TestCase { /** @@ -44,6 +47,9 @@ class TaxTest extends TestCase */ protected $invoice; + /** + * @inheritdoc + */ protected function setUp(): void { $this->objectManager = new ObjectManager($this); @@ -188,6 +194,8 @@ public function collectDataProvider() 'base_tax_amount' => 0.82, 'invoice' => new MagentoObject( [ + 'tax_amount' => 24.33, + 'base_tax_amount' => 24.33, 'shipping_tax_amount' => 2.45, 'base_shipping_tax_amount' => 2.45, 'shipping_discount_tax_compensation_amount' => 0, @@ -277,6 +285,8 @@ public function collectDataProvider() 'base_tax_amount' => 0.82, 'invoice' => new MagentoObject( [ + 'tax_amount' => 24.33 * $currencyRatio, + 'base_tax_amount' => 24.33, 'shipping_tax_amount' => 2.45 * $currencyRatio, 'base_shipping_tax_amount' => 2.45, 'shipping_discount_tax_compensation_amount' => 0, @@ -352,6 +362,8 @@ public function collectDataProvider() 'base_tax_amount' => 1.65, 'invoice' => new MagentoObject( [ + 'tax_amount' => 11.14, + 'base_tax_amount' => 11.14, 'shipping_tax_amount' => 1.24, 'base_shipping_tax_amount' => 1.24, 'shipping_discount_tax_compensation_amount' => 0, @@ -428,6 +440,8 @@ public function collectDataProvider() 'base_tax_amount' => 0.82, 'invoice' => new MagentoObject( [ + 'tax_amount' => 16.09, + 'base_tax_amount' => 16.09, 'shipping_tax_amount' => 1.24, 'base_shipping_tax_amount' => 1.24, 'shipping_discount_tax_compensation_amount' => 0, @@ -507,14 +521,6 @@ public function collectDataProvider() 'base_shipping_amount' => 0, 'tax_amount' => 0.76, 'base_tax_amount' => 0.76, - 'invoice' => new MagentoObject( - [ - 'shipping_tax_amount' => 0, - 'base_shipping_tax_amount' => 0, - 'shipping_discount_tax_compensation_amount' => 0, - 'base_shipping_discount_tax_compensation_amount' => 0, - ] - ), ], ], 'expected_results' => [ @@ -583,6 +589,8 @@ public function collectDataProvider() 'base_tax_amount' => 0.82, 'invoice' => new MagentoObject( [ + 'tax_amount' => 16.09, + 'base_tax_amount' => 16.09, 'shipping_tax_amount' => 1.24, 'base_shipping_tax_amount' => 1.24, 'shipping_discount_tax_compensation_amount' => 0, @@ -712,14 +720,6 @@ public function collectDataProvider() 'base_shipping_amount' => 0, 'tax_amount' => 0, 'base_tax_amount' => 0, - 'invoice' => new MagentoObject( - [ - 'shipping_tax_amount' => 0, - 'base_shipping_tax_amount' => 0, - 'shipping_discount_tax_compensation_amount' => 0, - 'base_shipping_discount_tax_compensation_amount' => 0, - ] - ), ], ], 'expected_results' => [ From 80fee6d722839ed48963ebfd16bff99167ebcad8 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Thu, 17 Dec 2020 15:50:46 +0200 Subject: [PATCH 283/346] MC-38822: stabilising test --- ...efrontAssertFixedCartDiscountAmountForBundleProductTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml index 65c8a4416c1a1..2a735fd196e76 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml @@ -18,6 +18,9 @@ <testCaseId value="MC-39480"/> </annotations> <before> + <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexCatalogInventory"> + <argument name="indices" value="cataloginventory_stock"/> + </actionGroup> <createData entity="SalesRuleNoCouponWithFixedDiscountWholeCart" stepKey="createSalesRule"/> <actionGroup ref="AdminCreateApiDynamicBundleProductAllOptionTypesActionGroup" stepKey="createBundleProduct"/> </before> From 42e25513694695a1383fa183a981566a4d717c8a Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Wed, 16 Dec 2020 17:14:57 -0600 Subject: [PATCH 284/346] MC-39895: PayPal PayflowPro redirect Parameter list format error - Fix checkout with Credit Card (Payflow Pro) fails if billing address has special characters (&, =) --- .../Paypal/Model/Payflow/Service/Gateway.php | 68 ++++++- .../Model/Payflow/Service/GatewayTest.php | 177 +++++++++++++++--- 2 files changed, 217 insertions(+), 28 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflow/Service/Gateway.php b/app/code/Magento/Paypal/Model/Payflow/Service/Gateway.php index 6a2229c3d55ca..374af021cbf38 100644 --- a/app/code/Magento/Paypal/Model/Payflow/Service/Gateway.php +++ b/app/code/Magento/Paypal/Model/Payflow/Service/Gateway.php @@ -85,7 +85,8 @@ public function postRequest(DataObject $request, ConfigInterface $config) ); $client->setConfig($clientConfig); $client->setMethod(\Zend_Http_Client::POST); - $client->setParameterPost($request->getData()); + $requestData = $this->prepareRequestData($request->getData()); + $client->setParameterPost($requestData); $client->setHeaders( [ 'X-VPS-VIT-CLIENT-CERTIFICATION-ID' => '33baf5893fc2123d8b191d2d011b7fdc', @@ -97,9 +98,7 @@ public function postRequest(DataObject $request, ConfigInterface $config) try { $response = $client->request(); - - $responseArray = []; - parse_str(strstr($response->getBody(), 'RESULT'), $responseArray); + $responseArray = $this->parseNVP(strstr($response->getBody(), 'RESULT')); $result->setData(array_change_key_case($responseArray, CASE_LOWER)); $result->setData('result_code', $result->getData('result')); @@ -115,7 +114,7 @@ public function postRequest(DataObject $request, ConfigInterface $config) } finally { $this->logger->debug( [ - 'request' => $request->getData(), + 'request' => $requestData, 'result' => $result->getData() ], (array)$config->getValue('getDebugReplacePrivateDataKeys'), @@ -125,4 +124,63 @@ public function postRequest(DataObject $request, ConfigInterface $config) return $result; } + + /** + * Add length tag to parameters name which contains special characters: =, & + * + * The length tag specifies the exact number of characters and spaces (number of bytes) that appear in the value + * eg ['COMPANYNAME[14]' => 'Ruff & Johnson')] + * + * @param array $data + * @return array + */ + private function prepareRequestData(array $data): array + { + $requestData = []; + foreach ($data as $k => $v) { + if (strpos($v, '&') !== false || strpos($v, '=') !== false) { + $requestData[$k . '[' . strlen($v) . ']'] = $v; + } else { + $requestData[$k] = $v; + } + } + return $requestData; + } + + /** + * Parse NVP string into array + * + * Use length tag (if present) to parse the key value. + * + * The length tag specifies the exact number of characters and spaces (number of bytes) that appear in the value + * e.g COMPANYNAME[14]=Ruff & Johnson + * e.g COMMENT1[7]=Level=5 + * + * @param string $nvp + * @return array + */ + private function parseNVP(string $nvp): array + { + $result = []; + while (strlen($nvp) > 0) { + $keyPos = strpos($nvp, '='); + if ($keyPos !== false) { + $key = substr($nvp, 0, $keyPos); + if (preg_match('/\[(\d+)]$/', $key, $keyParts)) { + $valueLength = (int) $keyParts[1]; + $key = substr($key, 0, strpos($key, '[')); + $result[$key] = substr($nvp, $keyPos + 1, $valueLength); + $valuePos = $keyPos + 1 + $valueLength; + } else { + $valuePos = strpos($nvp, '&') ? strpos($nvp, '&') : strlen($nvp); + $value = substr($nvp, $keyPos + 1, $valuePos - $keyPos - 1); + $result[$key] = $value; + } + $nvp = substr($nvp, $valuePos + 1); + } else { + $nvp = ''; + } + } + return $result; + } } diff --git a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/GatewayTest.php b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/GatewayTest.php index 194b708a0352b..a2d8111ec33c6 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/GatewayTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/Payflow/Service/GatewayTest.php @@ -17,27 +17,43 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; +use ReflectionMethod; +use Zend_Http_Client_Exception; +use Zend_Http_Response; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class GatewayTest extends TestCase { - /** @var Gateway|MockObject */ - protected $object; - - /** @var ZendClientFactory|MockObject */ - protected $httpClientFactoryMock; - - /** @var Random|MockObject */ - protected $mathRandomMock; - - /** @var Logger|MockObject */ - protected $loggerMock; - - /** @var ZendClient|MockObject */ - protected $zendClientMock; - + /** + * @var Gateway|MockObject + */ + private $object; + + /** + * @var ZendClientFactory|MockObject + */ + private $httpClientFactoryMock; + + /** + * @var Random|MockObject + */ + private $mathRandomMock; + + /** + * @var Logger|MockObject + */ + private $loggerMock; + + /** + * @var ZendClient|MockObject + */ + private $zendClientMock; + + /** + * @inheritdoc + */ protected function setUp(): void { $this->httpClientFactoryMock = $this->getMockBuilder(ZendClientFactory::class) @@ -66,24 +82,28 @@ protected function setUp(): void ); } - public function testPostRequestOk() + /** + * @param string $nvpResponse + * @param array $expectedResult + * @dataProvider postRequestOkDataProvider + */ + public function testPostRequestOk(string $nvpResponse, array $expectedResult): void { $configMap = [ ['getDebugReplacePrivateDataKeys', null, ['masked']], ['debug', null, true] ]; - $expectedResponse = 'RESULT=0&RESPMSG=Approved&SECURETOKEN=8ZIaw2&SECURETOKENID=2481d53'; /** @var ConfigInterface|MockObject $configInterfaceMock */ $configInterfaceMock = $this->getMockBuilder(ConfigInterface::class) ->getMockForAbstractClass(); - $zendResponseMock = $this->getMockBuilder(\Zend_Http_Response::class) + $zendResponseMock = $this->getMockBuilder(Zend_Http_Response::class) ->setMethods(['getBody']) ->disableOriginalConstructor() ->getMock(); $zendResponseMock->expects(static::once()) ->method('getBody') - ->willReturn($expectedResponse); + ->willReturn($nvpResponse); $this->zendClientMock->expects(static::once()) ->method('request') ->willReturn($zendResponseMock); @@ -98,8 +118,119 @@ public function testPostRequestOk() $result = $this->object->postRequest($object, $configInterfaceMock); - static::assertInstanceOf(DataObject::class, $result); - static::assertArrayHasKey('result_code', $result->getData()); + static::assertEquals($expectedResult, $result->toArray()); + } + + /** + * @return array[] + */ + public function postRequestOkDataProvider(): array + { + return [ + [ + 'RESULT=0&RESPMSG=Approved&SECURETOKEN=9tl4MmP46NUadl9pwCKFgfQjA' + . '&SECURETOKENID=vVWBMSNb9j0SLlYw4AbqBnKmuogtzNNC', + [ + 'result' => '0', + 'securetoken' => '9tl4MmP46NUadl9pwCKFgfQjA', + 'securetokenid' => 'vVWBMSNb9j0SLlYw4AbqBnKmuogtzNNC', + 'respmsg' => 'Approved', + 'result_code' => '0', + ] + ], + [ + 'RESULT=0&PNREF=A30A3A958244&RESPMSG=Approved&AUTHCODE=028PNI&AVSADDR=N&AVSZIP=N&HOSTCODE=A' + . '&PROCAVS=N&VISACARDLEVEL=12&TRANSTIME=2020-12-16 14:43:57&FIRSTNAME[4]=Joé' + . '&LASTNAME=O\'Reilly&COMPANYNAME[14]=Ruff & Johnson&COMMENT1[7]=Level=5' + . '&AMT=30.00&ACCT=1111&EXPDATE=1224&CARDTYPE=0&IAVS=N', + [ + 'result' => '0', + 'pnref' => 'A30A3A958244', + 'respmsg' => 'Approved', + 'authcode' => '028PNI', + 'avsaddr' => 'N', + 'avszip' => 'N', + 'hostcode' => 'A', + 'procavs' => 'N', + 'visacardlevel' => '12', + 'transtime' => '2020-12-16 14:43:57', + 'firstname' => 'Joé', + 'lastname' => 'O\'Reilly', + 'companyname' => 'Ruff & Johnson', + 'comment1' => 'Level=5', + 'amt' => '30.00', + 'acct' => '1111', + 'expdate' => '1224', + 'cardtype' => '0', + 'iavs' => 'N', + 'result_code' => '0', + ] + ], + ]; + } + + /** + * @param array $requestData + * @param string $requestBody + * @dataProvider requestBodyDataProvider + */ + public function testRequestBody(array $requestData, string $requestBody): void + { + $configMap = [ + ['getDebugReplacePrivateDataKeys', null, ['masked']], + ['debug', null, true] + ]; + + /** @var ConfigInterface|MockObject $configInterfaceMock */ + $configInterfaceMock = $this->getMockBuilder(ConfigInterface::class) + ->getMockForAbstractClass(); + $zendResponseMock = $this->getMockBuilder(Zend_Http_Response::class) + ->setMethods(['getBody']) + ->disableOriginalConstructor() + ->getMock(); + $zendResponseMock->expects(static::once()) + ->method('getBody') + ->willReturn('RESULT=0&RESPMSG=Approved'); + $this->zendClientMock->expects(static::once()) + ->method('request') + ->willReturn($zendResponseMock); + + $configInterfaceMock->expects(static::any()) + ->method('getValue') + ->willReturnMap($configMap); + $this->loggerMock->expects(static::once()) + ->method('debug'); + + $request = new DataObject($requestData); + $this->object->postRequest($request, $configInterfaceMock); + $method = new ReflectionMethod($this->zendClientMock, '_prepareBody'); + $method->setAccessible(true); + $this->assertEquals($requestBody, $method->invoke($this->zendClientMock)); + } + + /** + * @return array[] + */ + public function requestBodyDataProvider(): array + { + return [ + [ + [ + 'companyname' => 'Ruff & Johnson', + 'comment1' => 'Level=5', + 'shiptofirstname' => 'Joé', + 'shiptolastname' => 'O\'Reilly', + 'shiptostreet' => '4659 Rainbow Road', + 'shiptocity' => 'Los Angeles', + 'shiptostate' => 'CA', + 'shiptozip' => '90017', + 'shiptocountry' => 'US', + ], + 'companyname[14]=Ruff & Johnson&comment1[7]=Level=5&shiptofirstname=Joé&shiptolastname=O\'Reilly' + . '&shiptostreet=4659 Rainbow Road&shiptocity=Los Angeles&shiptostate=CA&shiptozip=90017' + . '&shiptocountry=US' + ] + ]; } public function testPostRequestFail() @@ -108,7 +239,7 @@ public function testPostRequestFail() /** @var ConfigInterface|MockObject $configInterfaceMock */ $configInterfaceMock = $this->getMockBuilder(ConfigInterface::class) ->getMockForAbstractClass(); - $zendResponseMock = $this->getMockBuilder(\Zend_Http_Response::class) + $zendResponseMock = $this->getMockBuilder(Zend_Http_Response::class) ->setMethods(['getBody']) ->disableOriginalConstructor() ->getMock(); @@ -116,7 +247,7 @@ public function testPostRequestFail() ->method('getBody'); $this->zendClientMock->expects(static::once()) ->method('request') - ->willThrowException(new \Zend_Http_Client_Exception()); + ->willThrowException(new Zend_Http_Client_Exception()); $object = new DataObject(); $this->object->postRequest($object, $configInterfaceMock); From c2c9b3684b410e76e0e29ece21997ea96e2727e9 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Thu, 17 Dec 2020 17:43:23 +0200 Subject: [PATCH 285/346] MC-38822: stabilising test --- ...frontAssertFixedCartDiscountAmountForBundleProductTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml index 2a735fd196e76..42e6d9e1d5b09 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Test/StorefrontAssertFixedCartDiscountAmountForBundleProductTest.xml @@ -18,11 +18,11 @@ <testCaseId value="MC-39480"/> </annotations> <before> + <createData entity="SalesRuleNoCouponWithFixedDiscountWholeCart" stepKey="createSalesRule"/> + <actionGroup ref="AdminCreateApiDynamicBundleProductAllOptionTypesActionGroup" stepKey="createBundleProduct"/> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindexCatalogInventory"> <argument name="indices" value="cataloginventory_stock"/> </actionGroup> - <createData entity="SalesRuleNoCouponWithFixedDiscountWholeCart" stepKey="createSalesRule"/> - <actionGroup ref="AdminCreateApiDynamicBundleProductAllOptionTypesActionGroup" stepKey="createBundleProduct"/> </before> <after> <deleteData createDataKey="createSalesRule" stepKey="deleteSalesRule"/> From b955411760da5f70e0bcc6a96462f9217e567e8a Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Thu, 17 Dec 2020 09:52:49 -0600 Subject: [PATCH 286/346] MC-39861: Customer is redirected to the blank page after using PayPal WPPHS payment on checkout --- .../Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php index d52c2501a565a..b3870c69b23f0 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Controller/Hostedpro/ReturnActionTest.php @@ -8,7 +8,7 @@ namespace Magento\Paypal\Controller\Hostedpro; use Magento\TestFramework\TestCase\AbstractController; -use Zend\Stdlib\Parameters; +use Laminas\Stdlib\Parameters; /** * Tests PayPal HostedPro return controller. From b07440c2f304658730298ef0d22d3825c2e8aa06 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Thu, 17 Dec 2020 11:06:03 -0600 Subject: [PATCH 287/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../Magento/UrlRewrite/Model/UrlRewrite.php | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php index d82781ee66450..cbefcd4c75597 100644 --- a/app/code/Magento/UrlRewrite/Model/UrlRewrite.php +++ b/app/code/Magento/UrlRewrite/Model/UrlRewrite.php @@ -145,23 +145,27 @@ public function setMetadata($metadata) */ private function getFinalTargetUrlRewrite(string $path, int $storeId): ?UrlRewriteService { + $urlRewriteTarget = $this->urlFinder->findOneByData( + [ + 'request_path' => $path, + 'store_id' => $storeId + ] + ); + + while ( + $urlRewriteTarget && + $urlRewriteTarget->getTargetPath() !== $urlRewriteTarget->getRequestPath() && + $urlRewriteTarget->getRedirectType() > 0 + ) { $urlRewriteTarget = $this->urlFinder->findOneByData( [ - 'request_path' => $path, - 'store_id' => $storeId + 'request_path' => $urlRewriteTarget->getTargetPath(), + 'store_id' => $urlRewriteTarget->getStoreId() ] ); + } - while ($urlRewriteTarget && $urlRewriteTarget->getRedirectType() > 0) { - $urlRewriteTarget = $this->urlFinder->findOneByData( - [ - 'request_path' => $urlRewriteTarget->getTargetPath(), - 'store_id' => $urlRewriteTarget->getStoreId() - ] - ); - } - - return $urlRewriteTarget; + return $urlRewriteTarget; } /** From 650aaa661afb97e17e86ca7ff7e5e6bfadb51192 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Thu, 17 Dec 2020 16:33:26 -0600 Subject: [PATCH 288/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../GraphQl/UrlRewrite/UrlResolverTest.php | 179 +++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php index 7aed048f1c4ce..5b84537dddf94 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php @@ -7,8 +7,14 @@ namespace Magento\GraphQl\UrlRewrite; +use Magento\Framework\Exception\AlreadyExistsException; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\ObjectManager; use Magento\TestFramework\TestCase\GraphQlAbstract; +use Magento\UrlRewrite\Model\ResourceModel\UrlRewrite as UrlRewriteResourceModel; +use Magento\UrlRewrite\Model\UrlFinderInterface; +use Magento\UrlRewrite\Model\UrlRewrite as UrlRewriteModel; +use Magento\UrlRewrite\Service\V1\Data\UrlRewrite as UrlRewriteService; /** * Test the GraphQL endpoint's URLResolver query to verify canonical URL's are correctly returned. @@ -20,7 +26,7 @@ class UrlResolverTest extends GraphQlAbstract protected function setUp(): void { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->objectManager = Bootstrap::getObjectManager(); } /** @@ -50,4 +56,175 @@ public function testNonExistentEntityUrlRewrite() ); $this->graphQlQuery($query); } + + /** + * Test for url rewrite to clean cache on rewrites update + * + * @magentoApiDataFixture Magento/Catalog/_files/product_with_category.php + * @magentoApiDataFixture Magento/Cms/_files/pages.php + * + * @dataProvider urlRewriteEntitiesDataProvider + * @param string $requestPath + * @throws AlreadyExistsException + */ + public function testUrlRewriteCleansCacheOnChange(string $requestPath) + { + + /** @var UrlRewriteResourceModel $urlRewriteResourceModel */ + $urlRewriteResourceModel = $this->objectManager->create(UrlRewriteResourceModel::class); + $storeId = 1; + $query = function ($requestUrl) { + return <<<QUERY +{ + urlResolver(url:"{$requestUrl}") + { + id + entity_uid + relative_url + type + redirectCode + } +} +QUERY; + }; + + // warming up urlResolver API response cache for entity and validate proper response + $apiResponse = $this->graphQlQuery($query($requestPath))['urlResolver']; + $this->assertEquals($requestPath, $apiResponse['relative_url']); + + $urlRewrite = $this->getUrlRewriteModelByRequestPath($requestPath, $storeId); + + // renaming entity request path and validating that API will not return cached response + $urlRewrite->setRequestPath('test' . $requestPath); + $urlRewriteResourceModel->save($urlRewrite); + $apiResponse = $this->graphQlQuery($query($requestPath))['urlResolver']; + $this->assertNull($apiResponse['relative_url']); + + // rolling back changes + $urlRewrite->setRequestPath($requestPath); + $urlRewriteResourceModel->save($urlRewrite); + } + + public function urlRewriteEntitiesDataProvider(): array + { + return [ + [ + 'simple-product-in-stock.html' + ], + [ + 'category-1.html' + ], + [ + 'page100' + ] + ]; + } + + /** + * Test for custom url rewrite to clean cache on update combinations + * + * @magentoApiDataFixture Magento/Catalog/_files/product_with_category.php + * @magentoApiDataFixture Magento/Cms/_files/pages.php + * + * @throws AlreadyExistsException + */ + public function testUrlRewriteCleansCacheForCustomRewrites() + { + + /** @var UrlRewriteResourceModel $urlRewriteResourceModel */ + $urlRewriteResourceModel = $this->objectManager->create(UrlRewriteResourceModel::class); + $storeId = 1; + $query = function ($requestUrl) { + return <<<QUERY +{ + urlResolver(url:"{$requestUrl}") + { + id + entity_uid + relative_url + type + redirectCode + } +} +QUERY; + }; + + $customRequestPath = 'test.html'; + $customSecondRequestPath = 'test2.html'; + $entitiesRequestPaths = [ + 'simple-product-in-stock.html', + 'category-1.html', + 'page100' + ]; + + // create custom url rewrite + $urlRewrite = $this->objectManager->create(UrlRewriteModel::class); + $urlRewrite->setEntityType('custom') + ->setRedirectType(302) + ->setStoreId($storeId) + ->setDescription(null) + ->setIsAutogenerated(0); + + // create second custom url rewrite and target it to previous one to check + // if proper final target url will be resolved + $secondUrlRewrite = $this->objectManager->create(UrlRewriteModel::class); + $secondUrlRewrite->setEntityType('custom') + ->setRedirectType(302) + ->setStoreId($storeId) + ->setRequestPath($customSecondRequestPath) + ->setTargetPath($customRequestPath) + ->setDescription(null) + ->setIsAutogenerated(0); + $urlRewriteResourceModel->save($secondUrlRewrite); + + foreach ($entitiesRequestPaths as $entityRequestPath) { + // updating custom rewrite for each entity + $urlRewrite->setRequestPath($customRequestPath) + ->setTargetPath($entityRequestPath); + $urlRewriteResourceModel->save($urlRewrite); + + // confirm that API returns non-cached response for the first custom rewrite + $apiResponse = $this->graphQlQuery($query($customRequestPath))['urlResolver']; + $this->assertEquals($entityRequestPath, $apiResponse['relative_url']); + + // confirm that API returns non-cached response for the second custom rewrite + $apiResponse = $this->graphQlQuery($query($customSecondRequestPath))['urlResolver']; + $this->assertEquals($entityRequestPath, $apiResponse['relative_url']); + } + + $urlRewriteResourceModel->delete($secondUrlRewrite); + + // delete custom rewrite and validate that API will not return cached response + $urlRewriteResourceModel->delete($urlRewrite); + $apiResponse = $this->graphQlQuery($query($customRequestPath))['urlResolver']; + $this->assertNull($apiResponse['relative_url']); + } + + /** + * Return UrlRewrite model instance by request_path + * + * @param string $requestPath + * @param int $storeId + * @return UrlRewriteModel + */ + private function getUrlRewriteModelByRequestPath(string $requestPath, int $storeId): UrlRewriteModel + { + /** @var UrlFinderInterface $urlFinder */ + $urlFinder = $this->objectManager->get(UrlFinderInterface::class); + + /** @var UrlRewriteService $urlRewriteService */ + $urlRewriteService = $urlFinder->findOneByData( + [ + 'request_path' => $requestPath, + 'store_id' => $storeId + ] + ); + + /** @var UrlRewriteModel $urlRewrite */ + $urlRewrite = $this->objectManager->create(UrlRewriteModel::class); + $urlRewrite->load($urlRewriteService->getUrlRewriteId()); + + return $urlRewrite; + } + } From 7448e601404e849b2902556bd4e338a19f873bb6 Mon Sep 17 00:00:00 2001 From: Serhii Kovalenko <ganster3012@gmail.com> Date: Wed, 16 Dec 2020 11:24:36 +0200 Subject: [PATCH 289/346] Fix length for additional column --- .../Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php index 96d9865998131..55e9924eb7fa0 100644 --- a/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php +++ b/lib/internal/Magento/Framework/Mview/View/AdditionalColumnsProcessor/DefaultProcessor.php @@ -66,7 +66,7 @@ public function processColumnForCLTable(Table $table, string $columnName): void $table->addColumn( $columnName, \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - null, + 255, ['unsigned' => true, 'nullable' => true, 'default' => null], $columnName ); From b372bdb84636b44e6c94e092584e64b64713e413 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Thu, 17 Dec 2020 18:51:39 -0600 Subject: [PATCH 290/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../GraphQl/UrlRewrite/UrlResolverTest.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php index 5b84537dddf94..e6ed14ae2685e 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php @@ -89,16 +89,16 @@ public function testUrlRewriteCleansCacheOnChange(string $requestPath) }; // warming up urlResolver API response cache for entity and validate proper response - $apiResponse = $this->graphQlQuery($query($requestPath))['urlResolver']; - $this->assertEquals($requestPath, $apiResponse['relative_url']); + $apiResponse = $this->graphQlQuery($query($requestPath)); + $this->assertEquals($requestPath, $apiResponse['urlResolver']['relative_url']); $urlRewrite = $this->getUrlRewriteModelByRequestPath($requestPath, $storeId); // renaming entity request path and validating that API will not return cached response $urlRewrite->setRequestPath('test' . $requestPath); $urlRewriteResourceModel->save($urlRewrite); - $apiResponse = $this->graphQlQuery($query($requestPath))['urlResolver']; - $this->assertNull($apiResponse['relative_url']); + $apiResponse = $this->graphQlQuery($query($requestPath)); + $this->assertNull($apiResponse['urlResolver']['relative_url']); // rolling back changes $urlRewrite->setRequestPath($requestPath); @@ -184,20 +184,20 @@ public function testUrlRewriteCleansCacheForCustomRewrites() $urlRewriteResourceModel->save($urlRewrite); // confirm that API returns non-cached response for the first custom rewrite - $apiResponse = $this->graphQlQuery($query($customRequestPath))['urlResolver']; - $this->assertEquals($entityRequestPath, $apiResponse['relative_url']); + $apiResponse = $this->graphQlQuery($query($customRequestPath)); + $this->assertEquals($entityRequestPath, $apiResponse['urlResolver']['relative_url']); // confirm that API returns non-cached response for the second custom rewrite - $apiResponse = $this->graphQlQuery($query($customSecondRequestPath))['urlResolver']; - $this->assertEquals($entityRequestPath, $apiResponse['relative_url']); + $apiResponse = $this->graphQlQuery($query($customSecondRequestPath)); + $this->assertEquals($entityRequestPath, $apiResponse['urlResolver']['relative_url']); } $urlRewriteResourceModel->delete($secondUrlRewrite); // delete custom rewrite and validate that API will not return cached response $urlRewriteResourceModel->delete($urlRewrite); - $apiResponse = $this->graphQlQuery($query($customRequestPath))['urlResolver']; - $this->assertNull($apiResponse['relative_url']); + $apiResponse = $this->graphQlQuery($query($customRequestPath)); + $this->assertNull($apiResponse['urlResolver']['relative_url']); } /** From 7edefd28ea67b16add4184008298e95ade8f1826 Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Wed, 16 Dec 2020 14:03:36 -0600 Subject: [PATCH 291/346] MC-39896: Catalog price rules are not included in CartItemPrices in the API - Adding customer group to the customer session - Adding api test --- .../Pricing/Price/UpdateCatalogRulePrice.php | 68 +++++++ .../CatalogRuleGraphQl/etc/graphql/di.xml | 12 ++ .../GraphQl/CatalogGraphQl/PriceRangeTest.php | 175 ++++++++++++++++++ ...t_with_tier_prices_for_logged_in_group.php | 48 +++++ ...er_prices_for_logged_in_group_rollback.php | 10 + ...th_tier_prices_for_not_logged_in_group.php | 48 +++++ ...rices_for_not_logged_in_group_rollback.php | 10 + .../catalog_rule_25_customer_group_all.php | 39 ++++ ...og_rule_25_customer_group_all_rollback.php | 35 ++++ ...alog_rule_50_registered_customer_group.php | 39 ++++ ..._50_registered_customer_group_rollback.php | 35 ++++ 11 files changed, 519 insertions(+) create mode 100644 app/code/Magento/CatalogRuleGraphQl/Plugin/Pricing/Price/UpdateCatalogRulePrice.php create mode 100644 app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogGraphQl/PriceRangeTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group.php create mode 100644 dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group_rollback.php diff --git a/app/code/Magento/CatalogRuleGraphQl/Plugin/Pricing/Price/UpdateCatalogRulePrice.php b/app/code/Magento/CatalogRuleGraphQl/Plugin/Pricing/Price/UpdateCatalogRulePrice.php new file mode 100644 index 0000000000000..61b9f70c49f04 --- /dev/null +++ b/app/code/Magento/CatalogRuleGraphQl/Plugin/Pricing/Price/UpdateCatalogRulePrice.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogRuleGraphQl\Plugin\Pricing\Price; + +use Magento\CatalogRule\Model\ResourceModel\Rule; +use Magento\CatalogRule\Pricing\Price\CatalogRulePrice; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; + +/** + * Class UpdateCatalogRulePrice + * + * Plugin to update catalog rule price based on customer group id + */ +class UpdateCatalogRulePrice +{ + /** + * @var TimezoneInterface + */ + private $dateTime; + + /** + * @var Rule + */ + private $ruleResource; + + /** + * @param TimezoneInterface $dateTime + * @param Rule $ruleResource + */ + public function __construct( + TimezoneInterface $dateTime, + Rule $ruleResource + ) { + $this->dateTime = $dateTime; + $this->ruleResource = $ruleResource; + } + + /** + * Returns catalog rule value for logged in customer group + * + * @param CatalogRulePrice $catalogRulePrice + * @param float|boolean $value + * @return float|boolean + */ + public function afterGetValue( + CatalogRulePrice $catalogRulePrice, + $value + ) { + $product = $catalogRulePrice->getProduct(); + if ($product && $product->getCustomerGroupId()) { + $store = $product->getStore(); + $value = $this->ruleResource->getRulePrice( + $this->dateTime->scopeDate($store->getId()), + $store->getWebsiteId(), + $product->getCustomerGroupId(), + $product->getId() + ); + $value = $value ? (float) $value : false; + } + + return $value; + } +} diff --git a/app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml b/app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml new file mode 100644 index 0000000000000..571783edece6c --- /dev/null +++ b/app/code/Magento/CatalogRuleGraphQl/etc/graphql/di.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\CatalogRule\Pricing\Price\CatalogRulePrice"> + <plugin name="update_catalog_rule_price_for_logged_in_customer_group" type="Magento\CatalogRuleGraphQl\Plugin\Pricing\Price\UpdateCatalogRulePrice"/> + </type> +</config> diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogGraphQl/PriceRangeTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogGraphQl/PriceRangeTest.php new file mode 100644 index 0000000000000..81b08f28431a6 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogGraphQl/PriceRangeTest.php @@ -0,0 +1,175 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\CatalogGraphQl; + +use Magento\GraphQl\GetCustomerAuthenticationHeader; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\TestCase\GraphQlAbstract; + +/** + * Test class to verify catalog price rule is applied for + * tier prices for different customer groups. + */ +class PriceRangeTest extends GraphQlAbstract +{ + /** + * @var ObjectManager|null + */ + private $objectManager; + + /** + * @var GetCustomerAuthenticationHeader + */ + private $getCustomerAuthenticationHeader; + + protected function setUp(): void + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->getCustomerAuthenticationHeader = $this->objectManager->get(GetCustomerAuthenticationHeader::class); + } + + /** + * Test for checking if catalog rule price has been applied for all customer group + * + * @magentoApiDataFixture Magento/Catalog/_files/product_simple.php + * @magentoApiDataFixture Magento/CatalogRule/_files/catalog_rule_25_customer_group_all.php + */ + public function testCheckIfCatalogRuleIsAppliedForTierPriceForAllGroups(): void + { + $productSku = 'simple'; + $query = $this->getProductSearchQuery($productSku); + + $response = $this->graphQlQuery($query); + + $this->assertNotEmpty($response['products']); + $priceRange = $response['products']['items'][0]['price_range']; + $this->assertEquals(10, $priceRange['minimum_price']['regular_price']['value']); + $this->assertEquals(7.5, $priceRange['minimum_price']['final_price']['value']); + $this->assertEquals(2.5, $priceRange['minimum_price']['discount']['amount_off']); + $this->assertEquals(25, $priceRange['minimum_price']['discount']['percent_off']); + $this->assertEquals(10, $priceRange['maximum_price']['regular_price']['value']); + $this->assertEquals(7.5, $priceRange['maximum_price']['final_price']['value']); + $this->assertEquals(2.5, $priceRange['maximum_price']['discount']['amount_off']); + $this->assertEquals(25, $priceRange['maximum_price']['discount']['percent_off']); + } + + /** + * Test for checking if catalog rule price has been applied for registered customer + * + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group.php + * @magentoApiDataFixture Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group.php + */ + public function testCheckIfCatalogRuleIsAppliedForTierPriceForRegisteredCustomer(): void + { + $productSku = 'simple'; + $query = $this->getProductSearchQuery($productSku); + $response = $this->graphQlQuery( + $query, + [], + '', + $this->getCustomerAuthenticationHeader->execute('customer@example.com', 'password') + ); + + $this->assertNotEmpty($response['products']); + $priceRange = $response['products']['items'][0]['price_range']; + $this->assertEquals(10, $priceRange['minimum_price']['regular_price']['value']); + $this->assertEquals(5, $priceRange['minimum_price']['final_price']['value']); + $this->assertEquals(5, $priceRange['minimum_price']['discount']['amount_off']); + $this->assertEquals(50, $priceRange['minimum_price']['discount']['percent_off']); + $this->assertEquals(10, $priceRange['maximum_price']['regular_price']['value']); + $this->assertEquals(5, $priceRange['maximum_price']['final_price']['value']); + $this->assertEquals(5, $priceRange['maximum_price']['discount']['amount_off']); + $this->assertEquals(50, $priceRange['maximum_price']['discount']['percent_off']); + } + + /** + * Test for checking if catalog rule price has been applied for guest + * + * @magentoApiDataFixture Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group.php + * @magentoApiDataFixture Magento/CatalogRule/_files/catalog_rule_10_off_not_logged.php + */ + public function testCheckIfCatalogRuleIsAppliedForTierPriceForGuest(): void + { + $productSku = 'simple'; + $query = $this->getProductSearchQuery($productSku); + $response = $this->graphQlQuery($query); + + $this->assertNotEmpty($response['products']); + $priceRange = $response['products']['items'][0]['price_range']; + $this->assertEquals(10, $priceRange['minimum_price']['regular_price']['value']); + $this->assertEquals(9, $priceRange['minimum_price']['final_price']['value']); + $this->assertEquals(1, $priceRange['minimum_price']['discount']['amount_off']); + $this->assertEquals(10, $priceRange['minimum_price']['discount']['percent_off']); + $this->assertEquals(10, $priceRange['maximum_price']['regular_price']['value']); + $this->assertEquals(9, $priceRange['maximum_price']['final_price']['value']); + $this->assertEquals(1, $priceRange['maximum_price']['discount']['amount_off']); + $this->assertEquals(10, $priceRange['maximum_price']['discount']['percent_off']); + } + + /** + * Get a query which user filter for product sku and returns price_tiers + * + * @param string $productSku + * @return string + */ + private function getProductSearchQuery(string $productSku): string + { + return <<<QUERY +{ + products(filter: {sku: {eq: "{$productSku}"}}) { + items { + name + sku + price_range { + minimum_price { + regular_price { + value + currency + } + final_price { + value + currency + } + discount { + amount_off + percent_off + } + } + maximum_price { + regular_price { + value + currency + } + final_price { + value + currency + } + discount { + amount_off + percent_off + } + } + } + price_tiers{ + discount{ + amount_off + percent_off + } + final_price{ + value + } + quantity + } + } + } +} +QUERY; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group.php new file mode 100644 index 0000000000000..35af54d574fd4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory; +use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; +use Magento\Customer\Model\Group; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php'); + +$objectManager = Bootstrap::getObjectManager(); +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$tierPriceFactory = $objectManager->get(ProductTierPriceInterfaceFactory::class); +$tpExtensionAttributesFactory = $objectManager->get(ProductTierPriceExtensionFactory::class); +$product = $productRepository->get('simple', false, null, true); +$adminWebsite = $objectManager->get(WebsiteRepositoryInterface::class)->get('admin'); +$tierPriceExtensionAttributes = $tpExtensionAttributesFactory->create()->setWebsiteId($adminWebsite->getId()); +$pricesForCustomerGroupsInput = [ + [ + 'customer_group_id' => '1', + 'percentage_value'=> null, + 'qty'=> 1, + 'value'=> 20 + ], + [ + 'customer_group_id' => '1', + 'percentage_value'=> null, + 'qty'=> 2, + 'value'=> 30 + ] +]; +$productTierPrices = []; +foreach ($pricesForCustomerGroupsInput as $price) { + $productTierPrices[] = $tierPriceFactory->create( + [ + 'data' => $price + ] + )->setExtensionAttributes($tierPriceExtensionAttributes); +} +$product->setTierPrices($productTierPrices); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group_rollback.php new file mode 100644 index 0000000000000..328c1e229da5c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_logged_in_group_rollback.php @@ -0,0 +1,10 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group.php new file mode 100644 index 0000000000000..cfb89b7de3305 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory; +use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; +use Magento\Customer\Model\Group; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php'); + +$objectManager = Bootstrap::getObjectManager(); +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$tierPriceFactory = $objectManager->get(ProductTierPriceInterfaceFactory::class); +$tpExtensionAttributesFactory = $objectManager->get(ProductTierPriceExtensionFactory::class); +$product = $productRepository->get('simple', false, null, true); +$adminWebsite = $objectManager->get(WebsiteRepositoryInterface::class)->get('admin'); +$tierPriceExtensionAttributes = $tpExtensionAttributesFactory->create()->setWebsiteId($adminWebsite->getId()); +$pricesForCustomerGroupsInput = [ + [ + 'customer_group_id' => Group::NOT_LOGGED_IN_ID, + 'percentage_value'=> null, + 'qty'=> 1, + 'value'=> 50 + ], + [ + 'customer_group_id' => Group::NOT_LOGGED_IN_ID, + 'percentage_value'=> null, + 'qty'=> 2, + 'value'=> 80 + ] +]; +$productTierPrices = []; +foreach ($pricesForCustomerGroupsInput as $price) { + $productTierPrices[] = $tierPriceFactory->create( + [ + 'data' => $price + ] + )->setExtensionAttributes($tierPriceExtensionAttributes); +} +$product->setTierPrices($productTierPrices); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group_rollback.php new file mode 100644 index 0000000000000..328c1e229da5c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/simple_product_with_tier_prices_for_not_logged_in_group_rollback.php @@ -0,0 +1,10 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all.php new file mode 100644 index 0000000000000..2c31c9a8d688a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +/** + * Creates simple Catalog Rule with the following data: + * active, applied to all products, without time limits, with 25% off for all customer groups + */ +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\Rule; +use Magento\Customer\Model\GroupManagement; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var $banner Rule */ +$catalogRule = Bootstrap::getObjectManager()->create( + Rule::class +); + +$catalogRule + ->setIsActive(1) + ->setName('Test Catalog Rule With 25 Percent Off') + ->setCustomerGroupIds('0') + ->setDiscountAmount(25) + ->setWebsiteIds([0 => 1]) + ->setSimpleAction('by_percent') + ->setStopRulesProcessing(false) + ->setSortOrder(0) + ->setSubIsEnable(0) + ->setSubDiscountAmount(0) + ->save(); + +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = Bootstrap::getObjectManager() + ->get(IndexBuilder::class); +$indexBuilder->reindexFull(); +sleep(1); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all_rollback.php new file mode 100644 index 0000000000000..73e6bbff46648 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_25_customer_group_all_rollback.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\CatalogRule\Api\CatalogRuleRepositoryInterface; +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\ResourceModel\Rule; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var Rule $catalogRuleResource */ +$catalogRuleResource = $objectManager->create(Rule::class); +$connection = $catalogRuleResource->getConnection(); + +//Retrieve rule id by name +$select = $connection->select(); +$select->from($catalogRuleResource->getMainTable(), 'rule_id'); +$select->where('name = ?', 'Test Catalog Rule With 25 Percent Off'); +$ruleId = $connection->fetchOne($select); + +try { + /** @var CatalogRuleRepositoryInterface $ruleRepository */ + $ruleRepository = $objectManager->create(CatalogRuleRepositoryInterface::class); + $ruleRepository->deleteById($ruleId); +} catch (\Exception $ex) { + //Nothing to remove +} +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); +$indexBuilder->reindexFull(); +sleep(1); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group.php new file mode 100644 index 0000000000000..d583dace85536 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +/** + * Creates simple Catalog Rule with the following data: + * active, applied to all products, without time limits, with 50% off for registered customer groups + */ +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\Rule; +use Magento\Customer\Model\GroupManagement; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var $banner Rule */ +$catalogRule = Bootstrap::getObjectManager()->create( + Rule::class +); + +$catalogRule + ->setIsActive(1) + ->setName('Test Catalog Rule With 50 Percent Off') + ->setCustomerGroupIds('1') + ->setDiscountAmount(50) + ->setWebsiteIds([0 => 1]) + ->setSimpleAction('by_percent') + ->setStopRulesProcessing(false) + ->setSortOrder(0) + ->setSubIsEnable(0) + ->setSubDiscountAmount(0) + ->save(); + +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = Bootstrap::getObjectManager() + ->get(IndexBuilder::class); +$indexBuilder->reindexFull(); +sleep(1); diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group_rollback.php new file mode 100644 index 0000000000000..46df301157b5c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogRule/_files/catalog_rule_50_registered_customer_group_rollback.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\CatalogRule\Api\CatalogRuleRepositoryInterface; +use Magento\CatalogRule\Model\Indexer\IndexBuilder; +use Magento\CatalogRule\Model\ResourceModel\Rule; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var Rule $catalogRuleResource */ +$catalogRuleResource = $objectManager->create(Rule::class); +$connection = $catalogRuleResource->getConnection(); + +//Retrieve rule id by name +$select = $connection->select(); +$select->from($catalogRuleResource->getMainTable(), 'rule_id'); +$select->where('name = ?', 'Test Catalog Rule With 50 Percent Off'); +$ruleId = $connection->fetchOne($select); + +try { + /** @var CatalogRuleRepositoryInterface $ruleRepository */ + $ruleRepository = $objectManager->create(CatalogRuleRepositoryInterface::class); + $ruleRepository->deleteById($ruleId); +} catch (\Exception $ex) { + //Nothing to remove +} +/** @var IndexBuilder $indexBuilder */ +$indexBuilder = $objectManager->get(IndexBuilder::class); +$indexBuilder->reindexFull(); +sleep(1); From 8b873ad45946dbefbd75038baea32df29c49980b Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Fri, 18 Dec 2020 10:46:21 +0200 Subject: [PATCH 292/346] MC-39864: [Magento Cloud] - Tax Miscalculation --- .../Model/Order/Creditmemo/Total/Tax.php | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index 9e6e8979e46ee..5fe4d0af7bd89 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -40,14 +40,14 @@ public function collect(Creditmemo $creditmemo) if ($orderItemQty) { /** Check item tax amount */ - $tax = ($orderItemTax - $orderItem->getTaxRefunded()); - $baseTax = ($baseOrderItemTax - $orderItem->getBaseTaxRefunded()); - $discountTaxCompensation = ($orderItem->getDiscountTaxCompensationInvoiced() - - $orderItem->getDiscountTaxCompensationRefunded()); - $baseDiscountTaxCompensation = ($orderItem->getBaseDiscountTaxCompensationInvoiced() - - $orderItem->getBaseDiscountTaxCompensationRefunded()); + $tax = $orderItemTax - $orderItem->getTaxRefunded(); + $baseTax = $baseOrderItemTax - $orderItem->getBaseTaxRefunded(); + $discountTaxCompensation = $orderItem->getDiscountTaxCompensationInvoiced() + - $orderItem->getDiscountTaxCompensationRefunded(); + $baseDiscountTaxCompensation = $orderItem->getBaseDiscountTaxCompensationInvoiced() + - $orderItem->getBaseDiscountTaxCompensationRefunded(); if (!$item->isLast()) { - $availableQty = ($orderItemQty - $orderItem->getQtyRefunded()); + $availableQty = $orderItemQty - $orderItem->getQtyRefunded(); $tax = $creditmemo->roundPrice($tax / $availableQty * $item->getQty()); $baseTax = $creditmemo->roundPrice(($baseTax / $availableQty * $item->getQty()), 'base'); $discountTaxCompensation = $creditmemo->roundPrice( @@ -76,10 +76,10 @@ public function collect(Creditmemo $creditmemo) if ($invoice = $creditmemo->getInvoice()) { // recalculate tax amounts in case if refund shipping value was changed if ($baseOrderShippingAmount && $creditmemo->getBaseShippingAmount() !== null) { - $taxFactor = ($creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount); - $shippingTaxAmount = ($invoice->getShippingTaxAmount() * $taxFactor); - $baseShippingTaxAmount = ($invoice->getBaseShippingTaxAmount() * $taxFactor); - $totalDiscountTaxCompensation += ($invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor); + $taxFactor = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount; + $shippingTaxAmount = $invoice->getShippingTaxAmount() * $taxFactor; + $baseShippingTaxAmount = $invoice->getBaseShippingTaxAmount() * $taxFactor; + $totalDiscountTaxCompensation += $invoice->getShippingDiscountTaxCompensationAmount() * $taxFactor; $baseTotalDiscountTaxCompensation += $invoice->getBaseShippingDiscountTaxCompensationAmnt() * $taxFactor; $shippingTaxAmount = $creditmemo->roundPrice($shippingTaxAmount); @@ -102,10 +102,10 @@ public function collect(Creditmemo $creditmemo) $shippingDelta = ($baseOrderShippingAmount - $baseOrderShippingRefundedAmount); if ($shippingDelta > $creditmemo->getBaseShippingAmount()) { - $part = ($creditmemo->getShippingAmount() / $orderShippingAmount); - $basePart = ($creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount); - $shippingTaxAmount = ($order->getShippingTaxAmount() * $part); - $baseShippingTaxAmount = ($order->getBaseShippingTaxAmount() * $basePart); + $part = $creditmemo->getShippingAmount() / $orderShippingAmount; + $basePart = $creditmemo->getBaseShippingAmount() / $baseOrderShippingAmount; + $shippingTaxAmount = $order->getShippingTaxAmount() * $part; + $baseShippingTaxAmount = $order->getBaseShippingTaxAmount() * $basePart; $shippingDiscountTaxCompensationAmount = $order->getShippingDiscountTaxCompensationAmount() * $part; $baseShippingDiscountTaxCompensationAmount = $order->getBaseShippingDiscountTaxCompensationAmnt() * $basePart; From 7d9d478b7c6b5dac52c7f4544b89612a0859d24b Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Fri, 18 Dec 2020 10:53:08 +0200 Subject: [PATCH 293/346] MC-39864: [Magento Cloud] - Tax Miscalculation --- app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index 5fe4d0af7bd89..0d1382a48e065 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -99,7 +99,7 @@ public function collect(Creditmemo $creditmemo) $baseShippingTaxAmount = 0; $shippingDiscountTaxCompensationAmount = 0; $baseShippingDiscountTaxCompensationAmount = 0; - $shippingDelta = ($baseOrderShippingAmount - $baseOrderShippingRefundedAmount); + $shippingDelta = $baseOrderShippingAmount - $baseOrderShippingRefundedAmount; if ($shippingDelta > $creditmemo->getBaseShippingAmount()) { $part = $creditmemo->getShippingAmount() / $orderShippingAmount; From acac6b2f488a29c8d23f6361ef64d66c43beed42 Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Thu, 10 Dec 2020 15:13:32 -0600 Subject: [PATCH 294/346] MC-39737: Reports: Review by Products - MFTF test and the solution --- .../reports_report_review_product_grid.xml | 4 +- ...inFilterProductReviewByNameActionGroup.xml | 20 +++++ .../Test/Mftf/Data/ProductReviewData.xml | 16 ++++ .../Section/AdminCreateNewReviewSection.xml | 5 ++ ...viewDateForReviewsByProductsReportTest.xml | 83 +++++++++++++++++++ 5 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 app/code/Magento/Review/Test/Mftf/ActionGroup/AdminFilterProductReviewByNameActionGroup.xml create mode 100644 app/code/Magento/Review/Test/Mftf/Test/AdminValidateLastReviewDateForReviewsByProductsReportTest.xml diff --git a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml index 26d0e8b13659d..b9d4572cd4868 100644 --- a/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml +++ b/app/code/Magento/Reports/view/adminhtml/layout/reports_report_review_product_grid.xml @@ -90,8 +90,8 @@ <arguments> <argument name="header" xsi:type="string" translate="true">Last Review</argument> <argument name="type" xsi:type="string">datetime</argument> - <argument name="id" xsi:type="string">created_at</argument> - <argument name="index" xsi:type="string">created_at</argument> + <argument name="id" xsi:type="string">last_review</argument> + <argument name="index" xsi:type="string">last_review</argument> <argument name="column_css_class" xsi:type="string">col-date</argument> <argument name="header_css_class" xsi:type="string">col-date</argument> </arguments> diff --git a/app/code/Magento/Review/Test/Mftf/ActionGroup/AdminFilterProductReviewByNameActionGroup.xml b/app/code/Magento/Review/Test/Mftf/ActionGroup/AdminFilterProductReviewByNameActionGroup.xml new file mode 100644 index 0000000000000..b0544081980bb --- /dev/null +++ b/app/code/Magento/Review/Test/Mftf/ActionGroup/AdminFilterProductReviewByNameActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminFilterProductReviewByNameActionGroup"> + <arguments> + <argument name="productName" type="string"/> + </arguments> + <waitForPageLoad stepKey="waitForGridToAppear"/> + <fillField userInput="{{productName}}" selector="{{AdminCreateNewReviewSection.filterProductName}}" stepKey="searchReview"/> + <click selector="{{AdminCreateNewReviewSection.searchButton}}" stepKey="startSearch"/> + <waitForPageLoad stepKey="waitForResults"/> + <see userInput="{{productName}}" selector="{{AdminCreateNewReviewSection.gridProductColumn}}" stepKey="assertReviewColumn"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Review/Test/Mftf/Data/ProductReviewData.xml b/app/code/Magento/Review/Test/Mftf/Data/ProductReviewData.xml index f66decd1b7bd0..ba2102d0ee1f1 100644 --- a/app/code/Magento/Review/Test/Mftf/Data/ProductReviewData.xml +++ b/app/code/Magento/Review/Test/Mftf/Data/ProductReviewData.xml @@ -16,4 +16,20 @@ <item>Default Store View</item> </array> </entity> + <entity name="firstSimpleProductReview"> + <data key="nickname" unique="suffix">user1</data> + <data key="title">Review title 1</data> + <data key="detail">Simple product review 1</data> + <array key="select_stores"> + <item>Default Store View</item> + </array> + </entity> + <entity name="secondSimpleProductReview"> + <data key="nickname" unique="suffix">user2</data> + <data key="title">Review title 2</data> + <data key="detail">Simple product review 2</data> + <array key="select_stores"> + <item>Default Store View</item> + </array> + </entity> </entities> diff --git a/app/code/Magento/Review/Test/Mftf/Section/AdminCreateNewReviewSection.xml b/app/code/Magento/Review/Test/Mftf/Section/AdminCreateNewReviewSection.xml index 3b17b20e9da1b..28eb3112f259a 100644 --- a/app/code/Magento/Review/Test/Mftf/Section/AdminCreateNewReviewSection.xml +++ b/app/code/Magento/Review/Test/Mftf/Section/AdminCreateNewReviewSection.xml @@ -18,8 +18,13 @@ <element name="submitReview" type="button" selector="#save_button"/> <element name="SuccessMessage" type="button" selector="div.message-success"/> <element name="gridProducts_filter_review_cnt" type="button" selector="#gridProducts_filter_review_cnt"/> + <element name="filterProductName" type="button" selector="#gridProducts_filter_name"/> <element name="searchButton" type="button" selector="//*[@id='gridProducts']//button[contains(@title, 'Search')]"/> <element name="gridReviewColumn" type="text" selector="//tbody//td[@data-column='review_cnt']"/> + <element name="gridLastReviewColumn" type="text" selector="//tbody//td[@data-column='created_at']"/> + <element name="gridProductColumn" type="text" selector="//tbody//td[@data-column='name']"/> + <element name="showReviewsButton" type="text" selector="//tbody//td[@data-column='action']"/> + <element name="grabLatestUserReviewDate" type="text" selector="//table[@class='data-grid']//tbody//tr[position()=1]//td[position()=3]"/> <element name="gridCustomer_filter_review_cnt" type="button" selector="#customers_grid_filter_review_cnt"/> <element name="CustomerSearchButton" type="button" selector="//*[@id='customers_grid']//button[contains(@title, 'Search')]"/> </section> diff --git a/app/code/Magento/Review/Test/Mftf/Test/AdminValidateLastReviewDateForReviewsByProductsReportTest.xml b/app/code/Magento/Review/Test/Mftf/Test/AdminValidateLastReviewDateForReviewsByProductsReportTest.xml new file mode 100644 index 0000000000000..3405314f24f78 --- /dev/null +++ b/app/code/Magento/Review/Test/Mftf/Test/AdminValidateLastReviewDateForReviewsByProductsReportTest.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminValidateLastReviewDateForReviewsByProductsReportTest"> + <annotations> + <features value="Review"/> + <stories value="Reports: Review by Products"/> + <title value="Admin Validate Last Review Date For Review by Products Reports"/> + <description value="Admin Validate Last Review Date For Review by Products Reports"/> + <severity value="MAJOR"/> + <useCaseId value="MC-39737"/> + <testCaseId value="MC-39838"/> + </annotations> + <before> + <!--Step1. Login as admin--> + <actionGroup ref="AdminLoginActionGroup" stepKey="LoginAsAdmin"/> + <!--Step2. Create product and Category--> + <createData stepKey="category" entity="SimpleSubCategory"/> + <createData stepKey="createProduct" entity="SimpleProduct"> + <requiredEntity createDataKey="category"/> + </createData> + </before> + <after> + <!--Step9. Delete newly created product reviews --> + <actionGroup ref="AdminOpenReviewsPageActionGroup" stepKey="openAllReviewsPage"/> + <actionGroup ref="AdminDeleteReviewsByUserNicknameActionGroup" stepKey="deleteFirstCustomerReview"> + <argument name="nickname" value="{{firstSimpleProductReview.nickname}}"/> + </actionGroup> + <actionGroup ref="AdminDeleteReviewsByUserNicknameActionGroup" stepKey="deleteSecondCustomerReview"> + <argument name="nickname" value="{{secondSimpleProductReview.nickname}}"/> + </actionGroup> + <!--Step10. delete Category and Products --> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <!--Step11. Admin Logout--> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/> + </after> + <!--Step3. Navigate to Marketing > User Content> All Review --> + <amOnPage url="{{AdminReviewsPage.url}}" stepKey="openReviewsPage"/> + <waitForPageLoad time="30" stepKey="waitForPageLoadCreatedReviewOne"/> + + <!--Step4. Add First and Second Review For Same Product--> + <actionGroup ref="AdminAddProductReviewActionGroup" stepKey="addFirstReview"> + <argument name="review" value="firstSimpleProductReview"/> + <argument name="sku" value="$$createProduct.sku$$"/> + </actionGroup> + <amOnPage url="{{AdminReviewsPage.url}}" stepKey="openReviewsPageAgain"/> + <waitForPageLoad time="30" stepKey="waitForPageLoadCreatedReviewTwo"/> + <actionGroup ref="AdminAddProductReviewActionGroup" stepKey="addSecondReview"> + <argument name="review" value="secondSimpleProductReview"/> + <argument name="sku" value="$$createProduct.sku$$"/> + </actionGroup> + <!--Step5. Navigate to Reports > Reviews > By Products --> + <actionGroup ref="AdminNavigateMenuActionGroup" stepKey="navigateToReportsByProductsPage"> + <argument name="menuUiId" value="{{AdminMenuReports.dataUiId}}"/> + <argument name="submenuUiId" value="{{AdminMenuReportsReviewsByProducts.dataUiId}}"/> + </actionGroup> + <!--Step6. Search product review by product name --> + <actionGroup ref="AdminFilterProductReviewByNameActionGroup" stepKey="navigateToReportsReview"> + <argument name="productName" value="$$createProduct.name$$"/> + </actionGroup> + <!--Step7. Click 'Show Reviews' to see review details--> + <grabTextFrom selector="{{AdminCreateNewReviewSection.gridLastReviewColumn}}" stepKey="grabLastReviewDate"/> + <click selector="{{AdminCreateNewReviewSection.showReviewsButton}}" stepKey="showReviewsPage"/> + <waitForPageLoad stepKey="waitForReviewListPageToLoad"/> + <!--Step8. Assert product last review date matches latest user review date--> + <fillField selector="{{AdminReviewGridSection.nickname}}" userInput="{{secondSimpleProductReview.nickname}}" stepKey="fillNickname"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFilters"/> + <waitForPageLoad stepKey="waitForGridViewPageToLoad"/> + <grabTextFrom selector="{{AdminCreateNewReviewSection.grabLatestUserReviewDate}}" stepKey="grabLatestUserReviewDate"/> + <assertEquals stepKey="assertReviewDate"> + <actualResult type="string">$grabLastReviewDate</actualResult> + <expectedResult type="string">$grabLatestUserReviewDate</expectedResult> + </assertEquals> + </test> +</tests> From 125b01a296c165afd53d8f13ceb35b0e13716702 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky <engcom-vendorworker-foxtrot@adobe.com> Date: Fri, 18 Dec 2020 11:52:56 +0200 Subject: [PATCH 295/346] magento/magento2#31131: [MFTF] Refactoring of AddOutOfStockProductToCompareListTest. --- .../AddOutOfStockProductToCompareListTest.xml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml index 7f4228a21f3d5..995fa4c7e5977 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AddOutOfStockProductToCompareListTest.xml @@ -20,6 +20,7 @@ <group value="Catalog"/> </annotations> <before> + <comment userInput="Adding the comment for preserving Backward Compatibility" stepKey="loginAsAdmin"/> <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockDisable.path}} {{CatalogInventoryOptionsShowOutOfStockDisable.value}}" stepKey="setConfigShowOutOfStockFalse"/> <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> @@ -35,8 +36,9 @@ <actionGroup ref="CliCacheFlushActionGroup" stepKey="flushCache"> <argument name="tags" value=""/> </actionGroup> - <deleteData createDataKey="product" stepKey="deleteProduct"/> - <deleteData createDataKey="category" stepKey="deleteCategory"/> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <comment userInput="Adding the comment for preserving Backward Compatibility" stepKey="logout"/> </after> <comment userInput="Open product page | Comment is kept to preserve the step key for backward compatibility" stepKey="openProdPage"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="goToSimpleProductPage"/> @@ -48,10 +50,10 @@ <comment userInput="'Add to compare' link is not available | Comment is kept to preserve the step key for backward compatibility" stepKey="addToCompareLinkAvailability"/> <dontSeeElement selector="{{StorefrontProductInfoMainSection.productAddToCompare}}" stepKey="dontSeeAddToCompareLink"/> - + <comment userInput="Turn on 'out of stock' config | Comment is kept to preserve the step key for backward compatibility" stepKey="onOutOfStockConfig"/> <magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockEnable.path}} {{CatalogInventoryOptionsShowOutOfStockEnable.value}}" stepKey="setConfigShowOutOfStockTrue"/> - + <comment userInput="Clear cache and reindex | Comment is kept to preserve the step key for backward compatibility" stepKey="cleanCache"/> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> <argument name="indices" value=""/> @@ -72,13 +74,13 @@ <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForProdAddToCmpList"/> <comment userInput="Assert success message | Comment is kept to preserve the step key for backward compatibility" stepKey="assertSuccessMsg"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="grabTextFromSuccessMessage"/> - + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="assertSuccessMessage"> <argument name="productVar" value="$$product$$"/> </actionGroup> <comment userInput="See product in the comparison list | Comment is kept to preserve the step key for backward compatibility" stepKey="seeProductInComparisonList"/> - + <actionGroup ref="StorefrontGoToCategoryPageActionGroup" stepKey="openCategoryPage"> <argument name="categoryName" value="$$category.name$$"/> </actionGroup> @@ -112,13 +114,13 @@ <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="grabTextFromSuccessMessage2"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="assertSuccessMessage2"/> - <comment userInput="Check that product displays on add to compare widget | Comment is kept to preserve the step key for backward compatibility" stepKey="checkProdNameOnWidget"/> + <comment userInput="Check that product displays on add to compare widget | Comment is kept to preserve the step key for backward compatibility" stepKey="checkProdNameOnWidget"/> <seeElement selector="{{StorefrontComparisonSidebarSection.ProductTitleByName($$product.name$$)}}" stepKey="seeProdNameOnCmpWidget"/> <comment userInput="See product in the compare page" stepKey="seeProductInComparePage"/> <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="navigateToComparePage2"/> <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForStorefrontProductComparePageLoad2"/> - + <actionGroup ref="SeeProductInComparisonListActionGroup" stepKey="seeProductInCompareList2"> <argument name="productVar" value="$$product$$"/> </actionGroup> From 59b446956348c8fdb421a1c61174cee018122fda Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Fri, 18 Dec 2020 15:13:00 +0200 Subject: [PATCH 296/346] MC-39765: No such entity with addressId, occurs randomly on visitors browser. System Log Generated --- .../Test/Unit/Observer/EmulateCustomerObserverTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php b/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php index 6c35ade65451b..2df36577b2931 100644 --- a/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php +++ b/app/code/Magento/Persistent/Test/Unit/Observer/EmulateCustomerObserverTest.php @@ -131,14 +131,14 @@ public function testExecuteWhenSessionPersistAndCustomerNotLoggedIn() $customerMock ->expects($this->once()) ->method('getDefaultShipping') - ->willReturn('shippingId'); + ->willReturn(12345); $customerMock ->expects($this->once()) ->method('getDefaultBilling') - ->willReturn('billingId'); + ->willReturn(12346); $valueMap = [ - ['shippingId', $defaultShippingAddressMock], - ['billingId', $defaultBillingAddressMock] + [12345, $defaultShippingAddressMock], + [12346, $defaultBillingAddressMock] ]; $this->addressRepositoryMock->expects($this->any())->method('getById')->willReturnMap($valueMap); $this->customerSessionMock From a391a9fe2833030f7a25730c289cc7f6746b41fe Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Fri, 18 Dec 2020 17:49:56 +0200 Subject: [PATCH 297/346] MC-35725: Price range of a Bundle Product is displayed incorrectly in the case of options with tier price --- .../Pricing/Price/BundleSelectionFactory.php | 5 +- .../Bundle/Pricing/Price/FinalPriceTest.php | 72 +++++++++++++++++ ...dle_product_with_tier_price_selections.php | 81 +++++++++++++++++++ ...ct_with_tier_price_selections_rollback.php | 33 ++++++++ .../three_simple_products_with_tier_price.php | 68 ++++++++++++++++ ...mple_products_with_tier_price_rollback.php | 31 +++++++ 6 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/Pricing/Price/FinalPriceTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections.php create mode 100644 dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price_rollback.php diff --git a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php index a28d721cc9a4e..52a024dc9fac3 100644 --- a/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php +++ b/app/code/Magento/Bundle/Pricing/Price/BundleSelectionFactory.php @@ -52,9 +52,12 @@ public function create( $quantity, array $arguments = [] ) { + $quantity = $quantity ? (float)$quantity : 1.; + $selection->setQty($quantity); + $arguments['bundleProduct'] = $bundleProduct; $arguments['saleableItem'] = $selection; - $arguments['quantity'] = $quantity ? (float)$quantity : 1.; + $arguments['quantity'] = $quantity; return $this->objectManager->create(self::SELECTION_CLASS_DEFAULT, $arguments); } diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Pricing/Price/FinalPriceTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Pricing/Price/FinalPriceTest.php new file mode 100644 index 0000000000000..6b1ab58035568 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/Pricing/Price/FinalPriceTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Bundle\Pricing\Price; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * 'Final Price' model integration tests. + * + * @magentoDbIsolation disabled + */ +class FinalPriceTest extends TestCase +{ + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @inheritDoc + */ + protected function setUp(): void + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + } + + /** + * Check minimal and maximal prices are calculated correctly for Bundle product selections with Tier Prices. + * + * @return void + * @magentoDataFixture Magento/Bundle/_files/bundle_product_with_tier_price_selections.php + */ + public function testGetPriceForBundleSelectionsWithTierPrices(): void + { + $priceModel = $this->getPriceModel('bundle_with_tier_price_selections'); + $this->assertEquals(15.0, $priceModel->getMinimalPrice()->getValue()); + $this->assertEquals(45.0, $priceModel->getMaximalPrice()->getValue()); + } + + /** + * Create and retrieve Price Model for provided Product SKU. + * + * @param string $productSku + * @return FinalPrice + */ + private function getPriceModel(string $productSku): FinalPrice + { + $bundleProduct = $this->productRepository->get($productSku); + + return $this->objectManager->create( + FinalPrice::class, + [ + 'saleableItem' => $bundleProduct, + 'quantity' => 0., + ] + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections.php new file mode 100644 index 0000000000000..5ef6daa5d11da --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Bundle\Model\Product\Price; +use Magento\Catalog\Api\Data\ProductInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Type\AbstractType; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Bundle\Model\PrepareBundleLinks; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/three_simple_products_with_tier_price.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var ProductInterfaceFactory $productFactory */ +$productFactory = $objectManager->get(ProductInterfaceFactory::class); +/** @var PrepareBundleLinks $prepareBundleLinks */ +$prepareBundleLinks = $objectManager->get(PrepareBundleLinks::class); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +$defaultWebsiteId = $storeManager->getWebsite('base')->getId(); + +$bundleProduct = $productFactory->create(); +$bundleProduct->setTypeId(Type::TYPE_BUNDLE) + ->setAttributeSetId($bundleProduct->getDefaultAttributeSetId()) + ->setWebsiteIds([$defaultWebsiteId]) + ->setName('Bundle Product') + ->setSku('bundle_with_tier_price_selections') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ) + ->setSkuType(0) + ->setPriceView(0) + ->setPriceType(Price::PRICE_TYPE_DYNAMIC) + ->setPrice(null) + ->setWeightType(0) + ->setShipmentType(AbstractType::SHIPMENT_TOGETHER); + +$bundleOptionsData = [ + [ + 'title' => 'Option 1', + 'default_title' => 'Option 1', + 'type' => 'select', + 'required' => 1, + ], +]; +$bundleSelectionsData = [ + [ + [ + 'sku' => 'simple_1', + 'selection_qty' => 3, + ], + [ + 'sku' => 'simple_2', + 'selection_qty' => 3, + ], + [ + 'sku' => 'simple_3', + 'selection_qty' => 3, + ], + ] +]; +$bundleProduct = $prepareBundleLinks->execute($bundleProduct, $bundleOptionsData, $bundleSelectionsData); +$productRepository->save($bundleProduct); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections_rollback.php new file mode 100644 index 0000000000000..e8d0ed513e839 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/bundle_product_with_tier_price_selections_rollback.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Registry; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance() + ->requireDataFixture('Magento/Catalog/_files/three_simple_products_with_tier_price_rollback.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +try { + $product = $productRepository->get('bundle_with_tier_price_selections', false, null, true); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price.php new file mode 100644 index 0000000000000..2b04935e46941 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\Data\ProductTierPriceExtensionFactory; +use Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Customer\Model\Group; +use Magento\Store\Api\Data\WebsiteInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductTierPriceInterfaceFactory $tierPriceFactory */ +$tierPriceFactory = $objectManager->get(ProductTierPriceInterfaceFactory::class); +/** @var ProductTierPriceExtensionFactory $tpExtensionAttributes */ +$tpExtensionAttributesFactory = $objectManager->get(ProductTierPriceExtensionFactory::class); + +/** @var WebsiteInterface $adminWebsite */ +$adminWebsite = $objectManager->get(WebsiteRepositoryInterface::class)->get('admin'); +$tierPriceExtensionAttributes = $tpExtensionAttributesFactory->create() + ->setWebsiteId($adminWebsite->getId()) + ->setPercentageValue(50); + +$tierPrice = $tierPriceFactory->create( + [ + 'data' => [ + 'customer_group_id' => Group::CUST_GROUP_ALL, + 'qty' => 2, + ], + ] +)->setExtensionAttributes($tierPriceExtensionAttributes); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$productNumber = 1; +foreach ([10, 20, 30] as $price) { + /** @var $product Product */ + $product = $objectManager->create(Product::class); + $product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId($product->getDefaultAttributeSetId()) + ->setWebsiteIds([1]) + ->setName('Simple Product ' . $productNumber) + ->setSku('simple_' . $productNumber) + ->setPrice($price) + ->setWeight(1) + ->setTierPrices([$tierPrice]) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_qty_decimal' => 0, + 'is_in_stock' => 1, + ] + ); + + $productRepository->save($product); + $productNumber++; +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price_rollback.php new file mode 100644 index 0000000000000..9dbf7a38371b6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/three_simple_products_with_tier_price_rollback.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Registry; +use Magento\TestFramework\Helper\Bootstrap; + +$objectManager = Bootstrap::getObjectManager(); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +foreach (['simple_1', 'simple_2', 'simple_3'] as $sku) { + try { + $product = $productRepository->get($sku, false, null, true); + $productRepository->delete($product); + } catch (NoSuchEntityException $e) { + //Product already removed + } +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From ed57b0ffdd696649a6b9d91d8f7dec5c615b6d8d Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Fri, 18 Dec 2020 10:51:14 -0600 Subject: [PATCH 298/346] MC-38810: Product Export CSV not parsed correctly in excel due to text area attributes content - fixed export - fixed import - added tests for export and import --- .../Model/Export/ProductTest.php | 58 ++++++++++++++++++ .../Model/Import/ProductTest.php | 61 +++++++++++++++++++ ...import_with_json_and_markup_attributes.csv | 3 + .../DependenciesShowFrameworkCommandTest.php | 4 +- .../expected/framework-dependencies.csv | 2 +- lib/internal/Magento/Framework/File/Csv.php | 7 ++- .../Framework/Filesystem/Driver/File.php | 7 ++- .../Filesystem/Driver/StatefulFile.php | 2 +- .../Framework/Filesystem/DriverInterface.php | 2 +- .../Framework/Filesystem/File/Read.php | 2 +- .../Filesystem/File/ReadInterface.php | 2 +- 11 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_json_and_markup_attributes.csv diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php index dd36f90757398..4d844a7c6f229 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Export/ProductTest.php @@ -108,6 +108,64 @@ public function testExport(): void $this->assertEquals(1, $occurrencesCount); } + /** + * Verify successful export of the product with custom attributes containing json and markup + * + * @magentoDataFixture Magento/Catalog/_files/product_text_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDbIsolation enabled + * @dataProvider exportWithJsonAndMarkupTextAttributeDataProvider + * @param string $attributeData + * @param string $expectedResult + * @return void + */ + public function testExportWithJsonAndMarkupTextAttribute(string $attributeData, string $expectedResult): void + { + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $productRepository = $objectManager->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $product = $productRepository->get('simple2'); + + /** @var \Magento\Eav\Model\Config $eavConfig */ + $eavConfig = $objectManager->get(\Magento\Eav\Model\Config::class); + $eavConfig->clear(); + $attribute = $eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'text_attribute'); + $attribute->setDefaultValue($attributeData); + /** @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository */ + $productAttributeRepository = $objectManager->get(\Magento\Catalog\Api\ProductAttributeRepositoryInterface::class); + $productAttributeRepository->save($attribute); + $product->setCustomAttribute('text_attribute', $attribute->getDefaultValue()); + $productRepository->save($product); + + $this->model->setWriter( + $this->objectManager->create( + \Magento\ImportExport\Model\Export\Adapter\Csv::class + ) + ); + $exportData = $this->model->export(); + $this->assertStringContainsString('Simple Product2', $exportData); + $this->assertStringContainsString($expectedResult, $exportData); + } + + /** + * @return array + */ + public function exportWithJsonAndMarkupTextAttributeDataProvider(): array + { + return [ + 'json' => [ + '{"type": "basic", "unit": "inch", "sign": "(\")", "size": "1.5\""}', + '"text_attribute={""type"": ""basic"", ""unit"": ""inch"", ""sign"": ""(\"")"", ""size"": ""1.5\""""}"' + ], + 'markup' => [ + '<div data-content>Element type is basic, measured in inches ' . + '(marked with sign (\")) with size 1.5\", mid-price range</div>', + '"text_attribute=<div data-content>Element type is basic, measured in inches ' . + '(marked with sign (\"")) with size 1.5\"", mid-price range</div>"' + ], + ]; + } + /** * @magentoDataFixture Magento/CatalogImportExport/_files/product_export_data_special_chars.php * @magentoDbIsolation enabled diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 3ca6754c77767..82d75cdce29c7 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -2344,6 +2344,67 @@ public function testProductWithWrappedAdditionalAttributes() ); } + /** + * @magentoDataFixture Magento/Catalog/_files/product_text_attribute.php + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled + * @dataProvider importWithJsonAndMarkupTextAttributeDataProvider + * @param string $productSku + * @param string $expectedResult + * @return void + */ + public function testImportWithJsonAndMarkupTextAttribute(string $productSku, string $expectedResult): void + { + // added by _files/product_import_with_json_and_markup_attributes.csv + $this->importedProducts = [ + 'SkuProductWithJson', + 'SkuProductWithMarkup', + ]; + + $importParameters =[ + 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, + 'entity' => 'catalog_product', + \Magento\ImportExport\Model\Import::FIELDS_ENCLOSURE => 0 + ]; + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/products_to_import_with_json_and_markup_attributes.csv', + 'directory' => $directory + ] + ); + $this->_model->setParameters($importParameters); + $this->_model->setSource($source); + $errors = $this->_model->validateData(); + $this->assertTrue($errors->getErrorsCount() == 0); + $this->_model->importData(); + $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Catalog\Api\ProductRepositoryInterface::class + ); + $product = $productRepository->get($productSku); + $this->assertEquals($expectedResult, $product->getData('text_attribute')); + } + + /** + * @return array + */ + public function importWithJsonAndMarkupTextAttributeDataProvider(): array + { + return [ + 'import of attribute with json' => [ + 'SkuProductWithJson', + '{"type": "basic", "unit": "inch", "sign": "(\")", "size": "1.5\""}' + ], + 'import of attribute with markup' => [ + 'SkuProductWithMarkup', + '<div data-content>Element type is basic, measured in inches ' . + '(marked with sign (\")) with size 1.5\", mid-price range</div>' + ], + ]; + } + /** * Import and check data from file. * diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_json_and_markup_attributes.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_json_and_markup_attributes.csv new file mode 100644 index 0000000000000..e8372c19c8ff2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_json_and_markup_attributes.csv @@ -0,0 +1,3 @@ +sku,product_type,name,price,attribute_set_code,categories,additional_attributes +SkuProductWithJson,simple,"Product With Json Attribute",100,Default,"Default Category/Category 1","text_attribute={""type"": ""basic"", ""unit"": ""inch"", ""sign"": ""(\"")"", ""size"": ""1.5\""""}" +SkuProductWithMarkup,simple,"Product With Markup Attribute",100,Default,"Default Category/Category 1","text_attribute=<div data-content>Element type is basic, measured in inches (marked with sign (\"")) with size 1.5\"", mid-price range</div>" diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/DependenciesShowFrameworkCommandTest.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/DependenciesShowFrameworkCommandTest.php index d07ec84b6eddc..b1c7843dfad32 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/DependenciesShowFrameworkCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/DependenciesShowFrameworkCommandTest.php @@ -70,11 +70,11 @@ public function testExecute() ); $this->assertStringContainsString('"Dependencies for each module:",' . PHP_EOL, $fileContents); $this->assertStringContainsString( - '"Magento\A",1' . PHP_EOL . '" -- Magento\Framework",2' . PHP_EOL, + 'Magento\A,1' . PHP_EOL . '" -- Magento\Framework",2' . PHP_EOL, $fileContents ); $this->assertStringContainsString( - '"Magento\B",1' . PHP_EOL . '" -- Magento\Framework",2' . PHP_EOL, + 'Magento\B,1' . PHP_EOL . '" -- Magento\Framework",2' . PHP_EOL, $fileContents ); } diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/expected/framework-dependencies.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/expected/framework-dependencies.csv index e1c5732b94dcb..9f358f3fa7a25 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/expected/framework-dependencies.csv +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/Dependency/_files/expected/framework-dependencies.csv @@ -2,7 +2,7 @@ ,3 "Dependencies for each module:", -"Magento\FirstModule",3 +Magento\FirstModule,3 " -- Magento\LibFirst",1 " -- Magento\LibSecond",2 " -- Magento\Third",1 diff --git a/lib/internal/Magento/Framework/File/Csv.php b/lib/internal/Magento/Framework/File/Csv.php index 1b1decdb5327c..e33b38562bf57 100644 --- a/lib/internal/Magento/Framework/File/Csv.php +++ b/lib/internal/Magento/Framework/File/Csv.php @@ -30,6 +30,11 @@ class Csv */ protected $_enclosure = '"'; + /** + * @var string + */ + private $escape = "\0"; + /** * @var File */ @@ -96,7 +101,7 @@ public function getData($file) } $fh = fopen($file, 'r'); - while ($rowData = fgetcsv($fh, $this->_lineLength, $this->_delimiter, $this->_enclosure)) { + while ($rowData = fgetcsv($fh, $this->_lineLength, $this->_delimiter, $this->_enclosure, $this->escape)) { $data[] = $rowData; } fclose($fh); diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/File.php b/lib/internal/Magento/Framework/Filesystem/Driver/File.php index bc08f67228849..7b508942c107d 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/File.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/File.php @@ -647,7 +647,7 @@ public function fileRead($resource, $length) * @return array|bool|null * @throws FileSystemException */ - public function fileGetCsv($resource, $length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\') + public function fileGetCsv($resource, $length = 0, $delimiter = ',', $enclosure = '"', $escape = "\0") { $result = @fgetcsv($resource, $length, $delimiter, $enclosure, $escape); if ($result === null) { @@ -801,7 +801,10 @@ public function filePutCsv($resource, array $data, $delimiter = ',', $enclosure } } - $result = @fputcsv($resource, $data, $delimiter, $enclosure); + // Escape symbol is needed to fix known issue in PHP broken fputcsv escaping functionality + // where backslash followed by double quote breaks file consistency + $escape = "\0"; + $result = @fputcsv($resource, $data, $delimiter, $enclosure, $escape); if (!$result) { throw new FileSystemException( new Phrase( diff --git a/lib/internal/Magento/Framework/Filesystem/Driver/StatefulFile.php b/lib/internal/Magento/Framework/Filesystem/Driver/StatefulFile.php index beeb1e928262c..9f69a38527ab3 100644 --- a/lib/internal/Magento/Framework/Filesystem/Driver/StatefulFile.php +++ b/lib/internal/Magento/Framework/Filesystem/Driver/StatefulFile.php @@ -642,7 +642,7 @@ public function fileRead($resource, $length) * @return array|bool|null * @throws FileSystemException */ - public function fileGetCsv($resource, $length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\') + public function fileGetCsv($resource, $length = 0, $delimiter = ',', $enclosure = '"', $escape = "\0") { $result = @fgetcsv($resource, $length, $delimiter, $enclosure, $escape); if ($result === null) { diff --git a/lib/internal/Magento/Framework/Filesystem/DriverInterface.php b/lib/internal/Magento/Framework/Filesystem/DriverInterface.php index afea4d3bc7b07..706077522c675 100644 --- a/lib/internal/Magento/Framework/Filesystem/DriverInterface.php +++ b/lib/internal/Magento/Framework/Filesystem/DriverInterface.php @@ -276,7 +276,7 @@ public function fileRead($resource, $length); * @return array|bool|null * @throws FileSystemException */ - public function fileGetCsv($resource, $length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\'); + public function fileGetCsv($resource, $length = 0, $delimiter = ',', $enclosure = '"', $escape = "\0"); /** * Returns position of read/write pointer diff --git a/lib/internal/Magento/Framework/Filesystem/File/Read.php b/lib/internal/Magento/Framework/Filesystem/File/Read.php index f48e50b7d693d..41e2cd255dd5d 100644 --- a/lib/internal/Magento/Framework/Filesystem/File/Read.php +++ b/lib/internal/Magento/Framework/Filesystem/File/Read.php @@ -124,7 +124,7 @@ public function readLine($length, $ending = null) * @param string $escape [optional] * @return array|bool|null */ - public function readCsv($length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\') + public function readCsv($length = 0, $delimiter = ',', $enclosure = '"', $escape = "\0") { return $this->driver->fileGetCsv($this->resource, $length, $delimiter, $enclosure, $escape); } diff --git a/lib/internal/Magento/Framework/Filesystem/File/ReadInterface.php b/lib/internal/Magento/Framework/Filesystem/File/ReadInterface.php index e27086709d8b1..4277e2b5693e7 100644 --- a/lib/internal/Magento/Framework/Filesystem/File/ReadInterface.php +++ b/lib/internal/Magento/Framework/Filesystem/File/ReadInterface.php @@ -46,7 +46,7 @@ public function readLine($length, $ending = null); * @param string $escape [optional] * @return array|bool false on end of file */ - public function readCsv($length = 0, $delimiter = ',', $enclosure = '"', $escape = '\\'); + public function readCsv($length = 0, $delimiter = ',', $enclosure = '"', $escape = "\0"); /** * Returns the current position From 876c8052f96d6770254277ff4dd39bce5e935d50 Mon Sep 17 00:00:00 2001 From: mastiuhin-olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Fri, 18 Dec 2020 22:26:18 +0200 Subject: [PATCH 299/346] MC-24495: Cannot save order with "file"-type address attribute. --- .../Model/Address/AbstractAddress.php | 7 +-- .../Customer/Model/Metadata/Form/File.php | 20 +++++++- .../Unit/Model/Metadata/Form/FileTest.php | 16 +++--- .../Adminhtml/Order/AddressSave.php | 50 ++++++++++++++++++- .../Magento/Sales/Model/AdminOrder/Create.php | 43 +++++++++++++++- 5 files changed, 119 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index 8421fc92f8c4a..d1364dc0aeba6 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -331,10 +331,11 @@ protected function _implodeArrayValues($value) return ''; } - $isScalar = false; + $isScalar = true; foreach ($value as $val) { - if (is_scalar($val)) { - $isScalar = true; + if (!is_scalar($val)) { + $isScalar = false; + break; } } if ($isScalar) { diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index 17cfc0325ef41..1add044c50c9e 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -100,6 +100,7 @@ public function __construct( FileProcessorFactory $fileProcessorFactory = null, IoFile $ioFile = null ) { + $value = $this->prepareFileValue($value); parent::__construct($localeDate, $logger, $attribute, $localeResolver, $value, $entityTypeCode, $isAjax); $this->urlEncoder = $urlEncoder; $this->_fileValidator = $fileValidator; @@ -302,11 +303,11 @@ public function validateValue($value) public function compactValue($value) { if ($this->getIsAjaxRequest()) { - return $this; + return ''; } // Remove outdated file (in the case of file uploader UI component) - if (empty($value) && !empty($this->_value)) { + if (!empty($this->_value) && !empty($value['delete'])) { $this->fileProcessor->removeUploadedFile($this->_value); return $value; } @@ -420,4 +421,19 @@ protected function getFileProcessor() { return $this->fileProcessor; } + + /** + * Prepare File value. + * + * @param array|string $value + * @return array|string + */ + private function prepareFileValue($value) + { + if (is_array($value) && isset($value['value'])) { + $value = $value['value']; + } + + return $value; + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php index 3c5016df230f9..b0e9805bb3d2a 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php @@ -347,7 +347,7 @@ public function testCompactValueIsAjax() ] ); - $this->assertSame($model, $model->compactValue('aValue')); + $this->assertSame('', $model->compactValue('aValue')); } public function testCompactValueNoDelete() @@ -362,12 +362,12 @@ public function testCompactValueNoDelete() ] ); - $this->fileProcessorMock->expects($this->once()) + $this->fileProcessorMock->expects($this->any()) ->method('removeUploadedFile') ->with('value') ->willReturnSelf(); - $this->assertSame([], $model->compactValue([])); + $this->assertSame('value', $model->compactValue([])); } public function testCompactValueDelete() @@ -377,11 +377,11 @@ public function testCompactValueDelete() $mediaDirMock = $this->getMockForAbstractClass( \Magento\Framework\Filesystem\Directory\WriteInterface::class ); - $mediaDirMock->expects($this->once()) + $mediaDirMock->expects($this->any()) ->method('delete') ->with(self::ENTITY_TYPE . '/' . 'value'); - $this->fileSystemMock->expects($this->once()) + $this->fileSystemMock->expects($this->any()) ->method('getDirectoryWrite') ->with(DirectoryList::MEDIA) ->will($this->returnValue($mediaDirMock)); @@ -394,7 +394,7 @@ public function testCompactValueDelete() ] ); - $this->assertSame('', $model->compactValue(['delete' => true])); + $this->assertIsArray($model->compactValue(['delete' => true])); } public function testCompactValueTmpFile() @@ -589,12 +589,12 @@ public function testCompactValueRemoveUiComponentValue() ] ); - $this->fileProcessorMock->expects($this->once()) + $this->fileProcessorMock->expects($this->any()) ->method('removeUploadedFile') ->with($value) ->willReturnSelf(); - $this->assertEquals([], $model->compactValue([])); + $this->assertEquals($value, $model->compactValue([])); } public function testCompactValueNoAction() diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php index 5633e16d7d3d0..03ff35d17775e 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php @@ -27,6 +27,7 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\App\ObjectManager; use Magento\Framework\App\Action\HttpPostActionInterface; +use Magento\Customer\Model\AttributeMetadataDataProvider; /** * Sales address save @@ -52,6 +53,11 @@ class AddressSave extends Order implements HttpPostActionInterface */ private $orderAddressRepository; + /** + * @var AttributeMetadataDataProvider + */ + private $attributeMetadataDataProvider; + /** * @param Context $context * @param Registry $coreRegistry @@ -82,7 +88,8 @@ public function __construct( OrderRepositoryInterface $orderRepository, LoggerInterface $logger, RegionFactory $regionFactory = null, - OrderAddressRepositoryInterface $orderAddressRepository = null + OrderAddressRepositoryInterface $orderAddressRepository = null, + AttributeMetadataDataProvider $attributeMetadataDataProvider = null ) { $this->regionFactory = $regionFactory ?: ObjectManager::getInstance()->get(RegionFactory::class); $this->orderAddressRepository = $orderAddressRepository ?: ObjectManager::getInstance() @@ -100,6 +107,8 @@ public function __construct( $orderRepository, $logger ); + $this->attributeMetadataDataProvider = $attributeMetadataDataProvider ?: ObjectManager::getInstance() + ->get(AttributeMetadataDataProvider::class); } /** @@ -115,6 +124,7 @@ public function execute() OrderAddressInterface::class )->load($addressId); $data = $this->getRequest()->getPostValue(); + $data = $this->truncateCustomFileAttributes($data); $data = $this->updateRegionData($data); $resultRedirect = $this->resultRedirectFactory->create(); if ($data && $address->getId()) { @@ -139,7 +149,7 @@ public function execute() return $resultRedirect->setPath('sales/*/'); } } - + /** * Update region data * @@ -155,4 +165,40 @@ private function updateRegionData($attributeValues) } return $attributeValues; } + + /** + * Truncates custom file attributes from a request. + * + * As custom file type attributes are not working workaround is introduced. + * + * @param array $data + * @return array + */ + private function truncateCustomFileAttributes(array $data): array + { + $foundedArrays = []; + + foreach ($data as $value) { + if (is_array($value)) { + $foundedArrays = $value; + } + } + + if (empty($foundedArrays)) { + return $data; + } + + $attributesList = $this->attributeMetadataDataProvider->loadAttributesCollection( + 'customer_address', + 'adminhtml_customer_address' + ); + $attributesList->addFieldToFilter('is_user_defined', 1); + $attributesList->addFieldToFilter('frontend_input', 'file'); + + foreach ($attributesList as $customFileAttribute) { + unset($data[$customFileAttribute->getAttributeCode()]); + } + + return $data; + } } diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 5d621f1632837..c8d3a506c2e67 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -7,10 +7,12 @@ namespace Magento\Sales\Model\AdminOrder; use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Customer\Api\Data\AttributeMetadataInterface; use Magento\Customer\Model\Metadata\Form as CustomerForm; use Magento\Framework\Api\ExtensibleDataObjectConverter; use Magento\Framework\App\ObjectManager; use Magento\Quote\Model\Quote\Address; +use Magento\Quote\Model\Quote\Address\CustomAttributeListInterface; use Magento\Quote\Model\Quote\Item; use Magento\Sales\Api\Data\OrderAddressInterface; use Magento\Sales\Model\Order; @@ -250,6 +252,11 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\ */ private $storeManager; + /** + * @var CustomAttributeListInterface + */ + private $customAttributeList; + /** * @param \Magento\Framework\ObjectManagerInterface $objectManager * @param \Magento\Framework\Event\ManagerInterface $eventManager @@ -282,6 +289,7 @@ class Create extends \Magento\Framework\DataObject implements \Magento\Checkout\ * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer * @param ExtensibleDataObjectConverter|null $dataObjectConverter * @param StoreManagerInterface $storeManager + * @param CustomAttributeListInterface|null $customAttributeList * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -315,7 +323,8 @@ public function __construct( array $data = [], \Magento\Framework\Serialize\Serializer\Json $serializer = null, ExtensibleDataObjectConverter $dataObjectConverter = null, - StoreManagerInterface $storeManager = null + StoreManagerInterface $storeManager = null, + CustomAttributeListInterface $customAttributeList = null ) { $this->_objectManager = $objectManager; $this->_eventManager = $eventManager; @@ -350,6 +359,8 @@ public function __construct( $this->dataObjectConverter = $dataObjectConverter ?: ObjectManager::getInstance() ->get(ExtensibleDataObjectConverter::class); $this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class); + $this->customAttributeList = $customAttributeList ?: ObjectManager::getInstance() + ->get(CustomAttributeListInterface::class); } /** @@ -1530,7 +1541,8 @@ public function setBillingAddress($address) $billingAddress->setData('save_in_address_book', $saveInAddressBook); $quote = $this->getQuote(); - if (!$quote->isVirtual() && $this->getShippingAddress()->getSameAsBilling()) { + $shippingAddress = $this->getShippingAddress(); + if (!$quote->isVirtual() && $shippingAddress->getSameAsBilling()) { $address['save_in_address_book'] = 0; $this->setShippingAddress($address); } @@ -1543,9 +1555,36 @@ public function setBillingAddress($address) } $quote->setBillingAddress($billingAddress); + if ($shippingAddress->getSameAsBilling()) { + $this->synchronizeAddressesFileAttributes(); + } + return $this; } + /** + * Synchronizes addresses file attributes. + * + * @return void + */ + private function synchronizeAddressesFileAttributes(): void + { + $billingAddress = $this->getBillingAddress(); + $shippingAddress = $this->getShippingAddress(); + + /** @var AttributeMetadataInterface[] $customAttributes */ + $customAttributes = $this->customAttributeList->getAttributes(); + foreach ($customAttributes as $attribute) { + $attributeCode = $attribute->getAttributeCode(); + if ($attribute->getFrontendInput() === 'file' && + !empty($billingAddress->getData($attributeCode)) && + empty($shippingAddress->getData($attributeCode)) + ) { + $shippingAddress->setData($attributeCode, $billingAddress->getData($attributeCode)); + } + } + } + /** * Set shipping method * From 5d69b324e160493f50dfb66e04721be1a97abc62 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Fri, 18 Dec 2020 16:32:25 -0600 Subject: [PATCH 300/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php index e6ed14ae2685e..e3f8cadb5f94a 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php @@ -98,7 +98,7 @@ public function testUrlRewriteCleansCacheOnChange(string $requestPath) $urlRewrite->setRequestPath('test' . $requestPath); $urlRewriteResourceModel->save($urlRewrite); $apiResponse = $this->graphQlQuery($query($requestPath)); - $this->assertNull($apiResponse['urlResolver']['relative_url']); + $this->assertNull($apiResponse); // rolling back changes $urlRewrite->setRequestPath($requestPath); @@ -197,7 +197,7 @@ public function testUrlRewriteCleansCacheForCustomRewrites() // delete custom rewrite and validate that API will not return cached response $urlRewriteResourceModel->delete($urlRewrite); $apiResponse = $this->graphQlQuery($query($customRequestPath)); - $this->assertNull($apiResponse['urlResolver']['relative_url']); + $this->assertNull($apiResponse); } /** From e24dcb909b78bda488e85ab7cbe78439207cc058 Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Fri, 18 Dec 2020 22:11:45 -0600 Subject: [PATCH 301/346] MC-39477: Cart Price rule not working where condition has Category "IS NOT" - Testing operator and the test --- app/code/Magento/Rule/Model/Condition/AbstractCondition.php | 2 +- .../Test/Unit/Model/Condition/AbstractConditionTest.php | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php index 67fc3590ac501..d5d3b80755360 100644 --- a/app/code/Magento/Rule/Model/Condition/AbstractCondition.php +++ b/app/code/Magento/Rule/Model/Condition/AbstractCondition.php @@ -838,7 +838,7 @@ public function validateAttribute($validatedValue) } } } elseif (is_array($value)) { - if (!is_array($validatedValue)) { + if (!is_array($validatedValue) || empty($validatedValue)) { return false; } $result = array_intersect($value, $validatedValue); diff --git a/app/code/Magento/Rule/Test/Unit/Model/Condition/AbstractConditionTest.php b/app/code/Magento/Rule/Test/Unit/Model/Condition/AbstractConditionTest.php index 3c55eacaff559..91f1c4b942f75 100644 --- a/app/code/Magento/Rule/Test/Unit/Model/Condition/AbstractConditionTest.php +++ b/app/code/Magento/Rule/Test/Unit/Model/Condition/AbstractConditionTest.php @@ -91,6 +91,10 @@ public function validateAttributeDataProvider() [1, '>=', '1', true], [1, '>=', 0, false], [0, '<', [1], false], + + [[1], '!{}', [], false], + [[1], '!{}', [1], false], + [[1], '!{}', [0], false], ]; } @@ -176,6 +180,8 @@ public function validateAttributeArrayInputTypeDataProvider() [[3], '{}', [], false, 'grid'], [1, '{}', 1, false, 'grid'], [1, '!{}', [1, 2, 3], false, 'grid'], + [1, '!{}', [], false, 'grid'], + [[1], '!{}', [], false, 'grid'], [[1], '{}', null, false, 'grid'], [null, '{}', null, true, 'input'], [null, '!{}', null, false, 'input'], From 9bb960fdda8d541073a45b8009206836ec4f0f31 Mon Sep 17 00:00:00 2001 From: Roman Flowers <flowers@adobe.com> Date: Sat, 19 Dec 2020 08:57:07 -0600 Subject: [PATCH 302/346] MC-39463: GraphQL caches urlResolver response and can return the old value after the url rewrite update --- .../testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php index e3f8cadb5f94a..4a4b617d7c28e 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php @@ -98,7 +98,7 @@ public function testUrlRewriteCleansCacheOnChange(string $requestPath) $urlRewrite->setRequestPath('test' . $requestPath); $urlRewriteResourceModel->save($urlRewrite); $apiResponse = $this->graphQlQuery($query($requestPath)); - $this->assertNull($apiResponse); + $this->assertNull($apiResponse['urlResolver']); // rolling back changes $urlRewrite->setRequestPath($requestPath); @@ -197,7 +197,7 @@ public function testUrlRewriteCleansCacheForCustomRewrites() // delete custom rewrite and validate that API will not return cached response $urlRewriteResourceModel->delete($urlRewrite); $apiResponse = $this->graphQlQuery($query($customRequestPath)); - $this->assertNull($apiResponse); + $this->assertNull($apiResponse['urlResolver']); } /** From d2745c59c545dff90a371528dab648b1df021dce Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Sat, 19 Dec 2020 21:45:23 -0600 Subject: [PATCH 303/346] MC-39763: Ratings data not rendering on review detail page - Adding review id with rating --- app/code/Magento/Review/Block/View.php | 3 +- .../Review/view/frontend/templates/view.phtml | 24 ++- .../Magento/Review/Block/ViewTest.php | 143 ++++++++++++++++++ .../_files/product_review_with_rating.php | 86 +++++++++++ .../product_review_with_rating_rollback.php | 11 ++ 5 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Review/Block/ViewTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating.php create mode 100644 dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating_rollback.php diff --git a/app/code/Magento/Review/Block/View.php b/app/code/Magento/Review/Block/View.php index fcfa11faa169d..bbdd246835f9e 100644 --- a/app/code/Magento/Review/Block/View.php +++ b/app/code/Magento/Review/Block/View.php @@ -103,9 +103,10 @@ public function getBackUrl() */ public function getRating() { + $reviewId = $this->getReviewId() ?: $this->getReviewData()->getId(); if (!$this->getRatingCollection()) { $ratingCollection = $this->_voteFactory->create()->getResourceCollection()->setReviewFilter( - $this->getReviewId() + $reviewId )->setStoreFilter( $this->_storeManager->getStore()->getId() )->addRatingInfo( diff --git a/app/code/Magento/Review/view/frontend/templates/view.phtml b/app/code/Magento/Review/view/frontend/templates/view.phtml index b51353b7df685..3fd2fc85f8853 100644 --- a/app/code/Magento/Review/view/frontend/templates/view.phtml +++ b/app/code/Magento/Review/view/frontend/templates/view.phtml @@ -33,16 +33,26 @@ <caption class="table-caption"><?= $block->escapeHtml(__('Product Rating')) ?></caption> <?php foreach ($block->getRating() as $_rating): ?> <?php if ($_rating->getPercent()): ?> + <?php $rating = ceil($_rating->getPercent()) ?> <tr> - <td class="label"><?= $block->escapeHtml(__($_rating->getRatingCode())) ?></td> + <td class="label" width="10%"> + <?= $block->escapeHtml(__($_rating->getRatingCode())) ?> + </td> <td class="value"> - <div class="rating-box"> - <div class="rating"/> + <?php $ratingId = $_rating->getRatingId() ?> + <div class="rating-summary item" + id="rating-div-<?= $block->escapeHtml($ratingId) ?>"> + <div class="rating-result" title="<?= /* @noEscape */ $rating ?>%"> + <span> + <span><?= /* @noEscape */ $rating ?>%</span> + </span> + </div> + <?= /* @noEscape */ $secureRenderer->renderStyleAsTag( + "width:" . /* @noEscape */ $rating . "%", + 'div#rating-div-'.$_rating->getRatingId(). + '>div.rating-result>span:first-child' + ) ?> </div> - <?= /* @noEscape */ $secureRenderer->renderStyleAsTag( - "width:" . /* @noEscape */ ceil($_rating->getPercent()) . "%;", - 'div.rating-box div.rating' - ) ?> </td> </tr> <?php endif; ?> diff --git a/dev/tests/integration/testsuite/Magento/Review/Block/ViewTest.php b/dev/tests/integration/testsuite/Magento/Review/Block/ViewTest.php new file mode 100644 index 0000000000000..74bb31d7cb48d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Review/Block/ViewTest.php @@ -0,0 +1,143 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Review\Block; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Customer\Model\Session; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Registry; +use Magento\Framework\View\LayoutInterface; +use Magento\Review\Model\ResourceModel\Review\Product\CollectionFactory; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; +use PHPUnit\Framework\TestCase; + +/** + * Test for displaying product review block. + * + * @magentoAppArea frontend + * @magentoDbIsolation enabled + */ +class ViewTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Session */ + private $customerSession; + + /** @var CollectionFactory */ + private $collectionFactory; + + /** @var Registry */ + private $registry; + + /** @var View */ + private $block; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->customerSession = $this->objectManager->get(Session::class); + $this->collectionFactory = $this->objectManager->get(CollectionFactory::class); + $this->registry = $this->objectManager->get(Registry::class); + $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(View::class); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + $this->registry->unregister('current_review'); + $this->registry->unregister('current_product'); + $this->registry->unregister('product'); + $this->customerSession->setCustomerId(null); + + parent::tearDown(); + } + + /** + * Test product review block + * + * @magentoDataFixture Magento/Review/_files/product_review_with_rating.php + * + * @return void + * @throws NoSuchEntityException + */ + public function testProductReviewBlock(): void + { + $this->customerSession->setCustomerId(1); + $review = $this->collectionFactory->create()->addCustomerFilter(1)->getFirstItem(); + $this->registerReview($review); + $this->assertNotNull($review->getReviewId()); + + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + /** @var ProductInterface $product */ + $product = $productRepository->get('simple', false, null, true); + $this->registerProduct($product); + + $blockHtml = $this->block->setReviewId($review->getReviewId())->toHtml(); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + sprintf("//div[contains(@class, 'details')]/h3[contains(text(), '%s')]", $review->getName()), + $blockHtml + ), + 'Product name wasn\'t found.' + ); + $ratings = $this->block->getRating(); + $this->assertCount(2, $ratings); + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath( + sprintf( + "//a[contains(@class, 'action back')]/span[contains(text(), '%s')]", + __('Back to Product Reviews') + ), + $blockHtml + ), + sprintf('%s button wasn\'t found.', __('Back to Product Reviews')) + ); + } + + /** + * Register the product + * + * @param ProductInterface $product + * @return void + */ + private function registerProduct(ProductInterface $product): void + { + $this->registry->unregister('current_product'); + $this->registry->unregister('product'); + $this->registry->register('current_product', $product); + $this->registry->register('product', $product); + } + + /** + * Register the current review + * + * @param Product $review + * @return void + */ + private function registerReview(Product $review): void + { + $this->registry->unregister('current_review'); + $this->registry->register('current_review', $review); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating.php b/dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating.php new file mode 100644 index 0000000000000..47a402ae44fc4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating.php @@ -0,0 +1,86 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Backend\App\Area\FrontNameResolver; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Model\CustomerRegistry; +use Magento\Framework\Registry; +use Magento\Review\Model\Rating; +use Magento\Review\Model\Rating\Option; +use Magento\Review\Model\ResourceModel\Review\Collection; +use Magento\Review\Model\Review; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Bootstrap::getInstance()->loadArea( + FrontNameResolver::AREA_CODE +); +Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer.php'); +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var CustomerRegistry $customerRegistry */ +$customerRegistry = $objectManager->create(CustomerRegistry::class); +$customer = $customerRegistry->retrieve(1); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$product = $productRepository->get('simple'); +$storeId = $objectManager->get( + StoreManagerInterface::class +)->getStore()->getId(); + +$review = $objectManager->create( + Review::class, + ['data' => [ + 'customer_id' => $customer->getId(), + 'title' => 'Review Summary', + 'detail' => 'Review text', + 'nickname' => 'Nickname', + ]] +); + +$review + ->setEntityId($review->getEntityIdByCode(Review::ENTITY_PRODUCT_CODE)) + ->setEntityPkValue($product->getId()) + ->setStatusId(Review::STATUS_APPROVED) + ->setStoreId($storeId) + ->setStores([$storeId]) + ->save(); + +$objectManager->get(Registry::class)->register( + 'review_data', + $review +); + +/** @var Collection $ratingCollection */ +$ratingCollection = $objectManager->create( + Rating::class +)->getCollection() + ->setPageSize(2) + ->setCurPage(1); + +foreach ($ratingCollection as $rating) { + $rating->setStores([$storeId])->setIsActive(1)->save(); +} + +foreach ($ratingCollection as $rating) { + $ratingOption = $objectManager + ->create(Option::class) + ->getCollection() + ->setPageSize(1) + ->setCurPage(2) + ->addRatingFilter($rating->getId()) + ->getFirstItem(); + $rating->setReviewId($review->getId()) + ->addOptionVote($ratingOption->getId(), $product->getId()); +} + +$objectManager->get(Registry::class)->register( + 'rating_data', + $ratingCollection->getFirstItem() +); diff --git a/dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating_rollback.php b/dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating_rollback.php new file mode 100644 index 0000000000000..0931d881a6fdc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Review/_files/product_review_with_rating_rollback.php @@ -0,0 +1,11 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); From 38fc6c6e907f1bc574e8d8365195b8a04ab3d1b8 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Mon, 21 Dec 2020 12:21:08 +0200 Subject: [PATCH 304/346] MC-39864: [Magento Cloud] - Tax Miscalculation --- .../Model/Order/Creditmemo/Total/Tax.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index 0d1382a48e065..eba84dcfb6364 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -182,9 +182,10 @@ private function calculateAllowedTax(Creditmemo $creditMemo): float { $invoice = $creditMemo->getInvoice(); $order = $creditMemo->getOrder(); - $amount = $invoice !== null ? $invoice->getTaxAmount() : $order->getTaxInvoiced(); + $amount = $invoice !== null ? $invoice->getTaxAmount() + : $order->getTaxInvoiced() - $order->getTaxRefunded(); - return (float) $amount - $order->getTaxRefunded() - $creditMemo->getTaxAmount(); + return (float) $amount - $creditMemo->getTaxAmount(); } /** @@ -197,9 +198,10 @@ private function calculateAllowedBaseTax(Creditmemo $creditMemo): float { $invoice = $creditMemo->getInvoice(); $order = $creditMemo->getOrder(); - $amount = $invoice !== null ? $invoice->getBaseTaxAmount() : $order->getBaseTaxInvoiced(); + $amount = $invoice !== null ? $invoice->getBaseTaxAmount() + : $order->getBaseTaxInvoiced() - $order->getBaseTaxRefunded(); - return (float) $amount - $order->getBaseTaxRefunded() - $creditMemo->getBaseTaxAmount(); + return (float) $amount - $creditMemo->getBaseTaxAmount(); } /** @@ -218,12 +220,12 @@ private function calculateAllowedDiscountTaxCompensation(Creditmemo $creditMemo) + $invoice->getShippingDiscountTaxCompensationAmount(); } else { $amount = $order->getDiscountTaxCompensationInvoiced() - + $order->getShippingDiscountTaxCompensationAmount(); + + $order->getShippingDiscountTaxCompensationAmount() + - $order->getDiscountTaxCompensationRefunded() + - $order->getShippingDiscountTaxCompensationRefunded(); } return (float) $amount - - $order->getDiscountTaxCompensationRefunded() - - $order->getShippingDiscountTaxCompensationRefunded() - $creditMemo->getDiscountTaxCompensationAmount() - $creditMemo->getShippingDiscountTaxCompensationAmount(); } @@ -244,12 +246,12 @@ private function calculateAllowedBaseDiscountTaxCompensation(Creditmemo $creditM + $invoice->getBaseShippingDiscountTaxCompensationAmnt(); } else { $amount = $order->getBaseDiscountTaxCompensationInvoiced() - + $order->getBaseShippingDiscountTaxCompensationAmnt(); + + $order->getBaseShippingDiscountTaxCompensationAmnt() + - $order->getBaseDiscountTaxCompensationRefunded() + - $order->getBaseShippingDiscountTaxCompensationRefunded(); } return (float) $amount - - $order->getBaseDiscountTaxCompensationRefunded() - - $order->getBaseShippingDiscountTaxCompensationRefunded() - $creditMemo->getBaseShippingDiscountTaxCompensationAmnt() - $creditMemo->getBaseDiscountTaxCompensationAmount(); } From e45a9447c469ca49489aa6314301140132571c43 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Mon, 21 Dec 2020 12:25:56 +0200 Subject: [PATCH 305/346] MC-39718: Process Manager always exits successfully if the amount of functions(i.e. indexer dimensions) is lower than the MAGE_INDEXER_THREADS_COUNT env variable --- .../Magento/Indexer/Model/ProcessManager.php | 5 +- .../Test/Unit/Model/ProcessManagerTest.php | 183 ++++++++++++++++++ 2 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Indexer/Test/Unit/Model/ProcessManagerTest.php diff --git a/app/code/Magento/Indexer/Model/ProcessManager.php b/app/code/Magento/Indexer/Model/ProcessManager.php index 2b25c8c6a3d15..b6fd158364dea 100644 --- a/app/code/Magento/Indexer/Model/ProcessManager.php +++ b/app/code/Magento/Indexer/Model/ProcessManager.php @@ -111,9 +111,12 @@ private function multiThreadsExecute($userFunctions) $this->startChildProcess($userFunction); } } - // phpcs:ignore Magento2.CodeAnalysis.EmptyBlock,Magento2.Functions.DiscouragedFunction + // phpcs:ignore Magento2.Functions.DiscouragedFunction while (pcntl_waitpid(0, $status) != -1) { //Waiting for the completion of child processes + if ($status > 0) { + $this->failInChildProcess = true; + } } if ($this->failInChildProcess) { diff --git a/app/code/Magento/Indexer/Test/Unit/Model/ProcessManagerTest.php b/app/code/Magento/Indexer/Test/Unit/Model/ProcessManagerTest.php new file mode 100644 index 0000000000000..9e9d2a5c81aba --- /dev/null +++ b/app/code/Magento/Indexer/Test/Unit/Model/ProcessManagerTest.php @@ -0,0 +1,183 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Indexer\Test\Unit\Model; + +use Magento\Framework\App\ResourceConnection; +use Magento\Indexer\Model\ProcessManager; +use PHPUnit\Framework\TestCase; + +/** + * Class covers process manager execution test logic + */ +class ProcessManagerTest extends TestCase +{ + /** + * @dataProvider functionsWithErrorProvider + * @param array $userFunctions + * @param int $threadsCount + * @return void + */ + public function testFailureInChildProcessHandleMultiThread(array $userFunctions, int $threadsCount): void + { + $connectionMock = $this->createMock(ResourceConnection::class); + $processManager = new ProcessManager( + $connectionMock, + null, + $threadsCount + ); + + try { + $processManager->execute($userFunctions); + $this->fail('Exception was not handled'); + } catch (\RuntimeException $exception) { + $this->assertEquals('Fail in child process', $exception->getMessage()); + } + } + + /** + * Closure functions data provider for multi thread execution + * + * @return array + * @SuppressWarnings(PHPMD.ExitExpression) + */ + public function functionsWithErrorProvider(): array + { + return [ + 'more_threads_than_functions' => [ + 'user_functions' => [ + // @codingStandardsIgnoreStart + function () { + exit(1); + }, + function () { + exit(0); + }, + function () { + exit(0); + }, + // @codingStandardsIgnoreEnd + ], + 'threads_count' => 4, + ], + 'less_threads_than_functions' => [ + 'user_functions' => [ + // @codingStandardsIgnoreStart + function () { + exit(1); + }, + function () { + exit(0); + }, + function () { + exit(0); + }, + // @codingStandardsIgnoreEnd + ], + 'threads_count' => 2, + ], + 'equal_threads_and_functions' => [ + 'user_functions' => [ + // @codingStandardsIgnoreStart + function () { + exit(1); + }, + function () { + exit(0); + }, + function () { + exit(0); + }, + // @codingStandardsIgnoreEnd + ], + 'threads_count' => 3, + ], + ]; + } + + /** + * @dataProvider successFunctionsProvider + * @param array $userFunctions + * @param int $threadsCount + * @return void + */ + public function testSuccessChildProcessHandleMultiThread(array $userFunctions, int $threadsCount): void + { + $connectionMock = $this->createMock(ResourceConnection::class); + $processManager = new ProcessManager( + $connectionMock, + null, + $threadsCount + ); + + try { + $processManager->execute($userFunctions); + } catch (\RuntimeException $exception) { + $this->fail('Exception was not handled'); + } + } + + /** + * Closure functions data provider for multi thread execution + * + * @return array + * @SuppressWarnings(PHPMD.ExitExpression) + */ + public function successFunctionsProvider(): array + { + return [ + 'more_threads_than_functions' => [ + 'user_functions' => [ + // @codingStandardsIgnoreStart + function () { + exit(0); + }, + function () { + exit(0); + }, + function () { + exit(0); + }, + // @codingStandardsIgnoreEnd + ], + 'threads_count' => 4, + ], + 'less_threads_than_functions' => [ + 'user_functions' => [ + // @codingStandardsIgnoreStart + function () { + exit(0); + }, + function () { + exit(0); + }, + function () { + exit(0); + }, + // @codingStandardsIgnoreEnd + ], + 'threads_count' => 2, + ], + 'equal_threads_and_functions' => [ + 'user_functions' => [ + // @codingStandardsIgnoreStart + function () { + exit(0); + }, + function () { + exit(0); + }, + function () { + exit(0); + }, + // @codingStandardsIgnoreEnd + ], + 'threads_count' => 3, + ], + ]; + } +} From d12f17198aec95cce37442933fc24264e6f540e8 Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Mon, 21 Dec 2020 14:19:11 +0200 Subject: [PATCH 306/346] MC-39037: Report tabs are not aligned and not able to view properly --- .../view/adminhtml/templates/widget/grid/extended.phtml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml index d4aa14250837f..4bdee469e2fa4 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml @@ -14,12 +14,13 @@ * getPagerVisibility() * getVarNamePage() */ -$numColumns = count($block->getColumns()); /** * @var \Magento\Backend\Block\Widget\Grid\Extended $block * @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */ +$numColumns = count($block->getColumns()); + ?> <?php if ($block->getCollection()): ?> <?php if ($block->canDisplayContainer()): ?> @@ -285,7 +286,9 @@ $numColumns = count($block->getColumns()); </table> </div> + <?php if ($block->canDisplayContainer()): ?> </div> + <?php endif; ?> <?php /** @var \Magento\Framework\Json\Helper\Data $jsonHelper */ $jsonHelper = $block->getData('jsonHelper'); From a2764054a2e661d5c052610d6945d9963ca63d5e Mon Sep 17 00:00:00 2001 From: mastiuhin-olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Mon, 21 Dec 2020 18:10:46 +0200 Subject: [PATCH 307/346] MC-24495: Cannot save order with "file"-type address attribute. --- .../Sales/Controller/Adminhtml/Order/AddressSave.php | 6 +++--- app/code/Magento/Sales/Model/AdminOrder/Create.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php index 03ff35d17775e..879baa948e919 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/AddressSave.php @@ -176,15 +176,15 @@ private function updateRegionData($attributeValues) */ private function truncateCustomFileAttributes(array $data): array { - $foundedArrays = []; + $foundArrays = []; foreach ($data as $value) { if (is_array($value)) { - $foundedArrays = $value; + $foundArrays = $value; } } - if (empty($foundedArrays)) { + if (empty($foundArrays)) { return $data; } diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index c8d3a506c2e67..6bd6e8e4e83e1 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -1576,9 +1576,9 @@ private function synchronizeAddressesFileAttributes(): void $customAttributes = $this->customAttributeList->getAttributes(); foreach ($customAttributes as $attribute) { $attributeCode = $attribute->getAttributeCode(); - if ($attribute->getFrontendInput() === 'file' && - !empty($billingAddress->getData($attributeCode)) && - empty($shippingAddress->getData($attributeCode)) + if ($attribute->getFrontendInput() === 'file' + && !empty($billingAddress->getData($attributeCode)) + && empty($shippingAddress->getData($attributeCode)) ) { $shippingAddress->setData($attributeCode, $billingAddress->getData($attributeCode)); } From 7b2440af23763655f6a9cd88fef8dde56f61d8a6 Mon Sep 17 00:00:00 2001 From: Arnob Saha <arnobsh@gmail.com> Date: Tue, 22 Dec 2020 05:13:34 -0600 Subject: [PATCH 308/346] MC-39617: Category Selector limit category upto 5 from the root - Adding JS code to process the tree --- .../templates/catalog/category/widget/tree.phtml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml index 6c92ddcf36243..cf64c57c720b7 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml @@ -77,6 +77,16 @@ $scriptString .= <<<script dataUrl: '{$block->escapeJs($block->escapeUrl($block->getLoadTreeUrl()))}' }); + categoryLoader.processResponse = function (response, parent, callback) { + var config = JSON.parse(response.responseText); + + this.buildCategoryTree(parent, config); + + if (typeof callback == "function") { + callback(this, parent); + } + }; + categoryLoader.buildCategoryTree = function(parent, config) { if (!config) return null; @@ -164,8 +174,10 @@ $scriptString .= <<<script }; categoryLoader.on("beforeload", function(treeLoader, node) { - $('{$block->escapeJs($_divId)}').fire('category:beforeLoad', {treeLoader:treeLoader}); treeLoader.baseParams.id = node.attributes.id; + treeLoader.baseParams.store = node.attributes.store; + treeLoader.baseParams.form_key = FORM_KEY; + $('{$block->escapeJs($_divId)}').fire('category:beforeLoad', {treeLoader:treeLoader}); }); tree{$block->escapeJs($block->getId())} = new Ext.tree.TreePanel.Enhanced('{$block->escapeJs($_divId)}', { From 6404f8d4b128967cf6913c0c00ec64875fcb23c1 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Tue, 22 Dec 2020 13:27:37 +0200 Subject: [PATCH 309/346] MC-40012: [On-Premise] Failure to allocate memory error when exporting customer addresses in admin --- .../Model/Export/Address.php | 109 +++++++++++++----- .../Test/Unit/Model/Export/AddressTest.php | 89 +++++--------- 2 files changed, 109 insertions(+), 89 deletions(-) diff --git a/app/code/Magento/CustomerImportExport/Model/Export/Address.php b/app/code/Magento/CustomerImportExport/Model/Export/Address.php index 03ce884a44d20..a2d38767432d9 100644 --- a/app/code/Magento/CustomerImportExport/Model/Export/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Export/Address.php @@ -5,6 +5,17 @@ */ namespace Magento\CustomerImportExport\Model\Export; +use Magento\Customer\Model\ResourceModel\Address\Collection; +use Magento\Customer\Model\ResourceModel\Address\CollectionFactory; +use Magento\Eav\Model\Config; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\DB\Select; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; +use Magento\ImportExport\Model\Export\Entity\AbstractEav; +use Magento\ImportExport\Model\Export\Factory; +use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory; +use Magento\Store\Model\StoreManagerInterface; + /** * Customer address export * @@ -13,7 +24,7 @@ * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @since 100.0.2 */ -class Address extends \Magento\ImportExport\Model\Export\Entity\AbstractEav +class Address extends AbstractEav { /**#@+ * Permanent column names @@ -93,7 +104,7 @@ class Address extends \Magento\ImportExport\Model\Export\Entity\AbstractEav /** * Customer addresses collection * - * @var \Magento\Customer\Model\ResourceModel\Address\Collection + * @var Collection */ protected $_addressCollection; @@ -118,31 +129,31 @@ class Address extends \Magento\ImportExport\Model\Export\Entity\AbstractEav * * @var array */ - protected $_customers = []; + protected $_customers; /** - * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig - * @param \Magento\Store\Model\StoreManagerInterface $storeManager - * @param \Magento\ImportExport\Model\Export\Factory $collectionFactory - * @param \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $resourceColFactory - * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate - * @param \Magento\Eav\Model\Config $eavConfig + * @param ScopeConfigInterface $scopeConfig + * @param StoreManagerInterface $storeManager + * @param Factory $collectionFactory + * @param CollectionByPagesIteratorFactory $resourceColFactory + * @param TimezoneInterface $localeDate + * @param Config $eavConfig * @param \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory $customerColFactory - * @param \Magento\CustomerImportExport\Model\Export\CustomerFactory $eavCustomerFactory - * @param \Magento\Customer\Model\ResourceModel\Address\CollectionFactory $addressColFactory + * @param CustomerFactory $eavCustomerFactory + * @param CollectionFactory $addressColFactory * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\ImportExport\Model\Export\Factory $collectionFactory, - \Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory $resourceColFactory, - \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate, - \Magento\Eav\Model\Config $eavConfig, + ScopeConfigInterface $scopeConfig, + StoreManagerInterface $storeManager, + Factory $collectionFactory, + CollectionByPagesIteratorFactory $resourceColFactory, + TimezoneInterface $localeDate, + Config $eavConfig, \Magento\Customer\Model\ResourceModel\Customer\CollectionFactory $customerColFactory, - \Magento\CustomerImportExport\Model\Export\CustomerFactory $eavCustomerFactory, - \Magento\Customer\Model\ResourceModel\Address\CollectionFactory $addressColFactory, + CustomerFactory $eavCustomerFactory, + CollectionFactory $addressColFactory, array $data = [] ) { parent::__construct( @@ -178,19 +189,20 @@ public function __construct( */ protected function _initCustomers() { - if (empty($this->_customers)) { + if ($this->_customers === null) { + $this->_customers = []; // add customer default addresses column name to customer attribute mapping array $this->_customerCollection->addAttributeToSelect(self::$_defaultAddressAttributeMapping); // filter customer collection $this->_customerCollection = $this->_customerEntity->filterEntityCollection($this->_customerCollection); - $customers = []; - $addCustomer = function (\Magento\Customer\Model\Customer $customer) use (&$customers) { - $customers[$customer->getId()] = $customer->getData(); - }; + $selectIds = $this->_customerCollection->getAllIdsSql(); + $this->_customerCollection->setPageSize($this->_pageSize); + $pageCount = $this->_customerCollection->getLastPageNumber(); - $this->_byPagesIterator->iterate($this->_customerCollection, $this->_pageSize, [$addCustomer]); - $this->_customers = $customers; + for ($pageNum = 1; $pageNum <= $pageCount; $pageNum++) { + $this->_customers += $this->loadCustomerData($selectIds, $pageNum); + } } return $this; @@ -211,7 +223,7 @@ protected function _getHeaderColumns() /** * Get customers collection * - * @return \Magento\Customer\Model\ResourceModel\Address\Collection + * @return Collection */ protected function _getEntityCollection() { @@ -227,7 +239,7 @@ public function export() { // skip and filter by customer address attributes $this->_prepareEntityCollection($this->_getEntityCollection()); - $this->_getEntityCollection()->setCustomerFilter(array_keys($this->_customers)); + $this->_getEntityCollection()->setCustomerFilter(array_keys($this->getCustomers())); // prepare headers $this->getWriter()->setHeaderCols($this->_getHeaderColumns()); @@ -248,7 +260,7 @@ public function exportItem($item) $row = $this->_addAttributeValuesToRow($item); /** @var $customer \Magento\Customer\Model\Customer */ - $customer = $this->_customers[$item->getParentId()]; + $customer = $this->getCustomers()[$item->getParentId()]; // Fill row with default address attributes values foreach (self::$_defaultAddressAttributeMapping as $columnName => $attributeCode) { @@ -274,10 +286,8 @@ public function exportItem($item) */ public function setParameters(array $parameters) { - // push filters from post into export customer model + // push filters from post into export customer model $this->_customerEntity->setParameters($parameters); - $this->_initCustomers(); - return parent::setParameters($parameters); } @@ -290,4 +300,39 @@ public function getEntityTypeCode() { return $this->getAttributeCollection()->getEntityTypeCode(); } + + /** + * Get Customers Data + * + * @return array + */ + private function getCustomers(): array + { + $this->_initCustomers(); + return $this->_customers; + } + + /** + * Load Customers Data + * + * @param Select $selectIds + * @param int $pageNum + * @return array + */ + private function loadCustomerData(Select $selectIds, int $pageNum = 0): array + { + $select = $this->_customerCollection->getConnection()->select(); + $select->from( + ['customer' => $this->_customerCollection->getTable('customer_entity')], + ['entity_id', 'email', 'store_id', 'website_id', 'default_billing', 'default_shipping'] + )->where( + 'customer.entity_id IN (?)', $selectIds + ); + + if ($pageNum > 0) { + $select->limitPage($pageNum, $this->_pageSize); + } + + return $this->_customerCollection->getConnection()->fetchAssoc($select); + } } diff --git a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Export/AddressTest.php b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Export/AddressTest.php index f40d71d2efa7c..2d8c105d2b29c 100644 --- a/app/code/Magento/CustomerImportExport/Test/Unit/Model/Export/AddressTest.php +++ b/app/code/Magento/CustomerImportExport/Test/Unit/Model/Export/AddressTest.php @@ -7,10 +7,7 @@ namespace Magento\CustomerImportExport\Test\Unit\Model\Export; -use Magento\Customer\Model\AddressFactory; -use Magento\Customer\Model\Config\Share; -use Magento\Customer\Model\GroupFactory; -use Magento\Customer\Model\ResourceModel\Customer; +use Magento\Customer\Model\ResourceModel\Customer\Collection as CustomerCollection; use Magento\Customer\Model\ResourceModel\Customer\CollectionFactory; use Magento\CustomerImportExport\Model\Export\Address; use Magento\CustomerImportExport\Model\Export\CustomerFactory; @@ -19,9 +16,10 @@ use Magento\Eav\Model\Entity\TypeFactory; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Data\Collection; -use Magento\Framework\Data\Collection\AbstractDb; use Magento\Framework\Data\Collection\EntityFactory; use Magento\Framework\DataObject; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\DB\Select; use Magento\Framework\Model\AbstractModel; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -30,7 +28,6 @@ use Magento\ImportExport\Model\ResourceModel\CollectionByPagesIteratorFactory; use Magento\Store\Model\Store; use Magento\Store\Model\StoreManager; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; /** @@ -82,7 +79,7 @@ class AddressTest extends TestCase /** * ObjectManager helper * - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + * @var ObjectManager */ protected $_objectManager; @@ -93,6 +90,9 @@ class AddressTest extends TestCase */ protected $_model; + /** + * @inheritdoc + */ protected function setUp(): void { $storeManager = $this->createMock(StoreManager::class); @@ -119,6 +119,9 @@ protected function setUp(): void ); } + /** + * @inheritdoc + */ protected function tearDown(): void { unset($this->_model); @@ -132,8 +135,9 @@ protected function tearDown(): void */ protected function _getModelDependencies() { - $translator = $this->createMock(\stdClass::class); + $pageSize = 1; + $translator = $this->createMock(\stdClass::class); $entityFactory = $this->createMock(EntityFactory::class); /** @var Collection|TestCase $attributeCollection */ @@ -167,34 +171,35 @@ protected function _getModelDependencies() $attributeCollection->addItem($attribute); } - $byPagesIterator = $this->getMockBuilder(\stdClass::class)->addMethods(['iterate']) - ->disableOriginalConstructor() - ->getMock(); - $byPagesIterator->expects( - $this->once() - )->method( - 'iterate' - )->willReturnCallback( - [$this, 'iterate'] - ); - - $customerCollection = $this->getMockBuilder(AbstractDb::class) - ->setMethods(['addAttributeToSelect']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); + $connection = $this->createMock(AdapterInterface::class); + $customerCollection = $this->createMock(CustomerCollection::class); + $customerCollection->method('getConnection')->willReturn($connection); + $customerCollection->expects($this->once())->method('setPageSize')->with($pageSize); + $customerCollection->method('getLastPageNumber')->willReturn(1); + $allIdsSelect = $this->createMock(Select::class); + $customerCollection->method('getAllIdsSql')->willReturn($allIdsSelect); + + $customerSelect = $this->createMock(Select::class); + $customerSelect->method('from')->willReturnSelf(); + $customerSelect->expects($this->once()) + ->method('where') + ->with('customer.entity_id IN (?)', $allIdsSelect) + ->willReturnSelf(); + $customerSelect->expects($this->once())->method('limitPage')->with(1, $pageSize); + $connection->method('select')->willReturn($customerSelect); + $connection->method('fetchAssoc')->with($customerSelect)->willReturn([1 => $this->_customerData]); $customerEntity = $this->getMockBuilder(\stdClass::class) ->addMethods(['filterEntityCollection', 'setParameters']) ->disableOriginalConstructor() ->getMock(); - $customerEntity->expects($this->any())->method('filterEntityCollection')->willReturnArgument(0); - $customerEntity->expects($this->any())->method('setParameters')->willReturnSelf(); + $customerEntity->method('filterEntityCollection')->willReturnArgument(0); + $customerEntity->method('setParameters')->willReturnSelf(); $data = [ 'translator' => $translator, 'attribute_collection' => $attributeCollection, - 'page_size' => 1, - 'collection_by_pages_iterator' => $byPagesIterator, + 'page_size' => $pageSize, 'entity_type_id' => 1, 'customer_collection' => $customerCollection, 'customer_entity' => $customerEntity, @@ -228,36 +233,6 @@ public function getWebsites($withDefault = false) return $websites; } - /** - * Iterate stub - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @param AbstractDb $collection - * @param int $pageSize - * @param array $callbacks - */ - public function iterate(AbstractDb $collection, $pageSize, array $callbacks) - { - $resource = $this->createPartialMock(Customer::class, ['getIdFieldName']); - $resource->expects($this->any())->method('getIdFieldName')->willReturn('id'); - $arguments = [ - 'data' => $this->_customerData, - 'resource' => $resource, - $this->createMock(Share::class), - $this->createMock(AddressFactory::class), - $this->createMock(\Magento\Customer\Model\ResourceModel\Address\CollectionFactory::class), - $this->createMock(GroupFactory::class), - $this->createMock(\Magento\Customer\Model\AttributeFactory::class), - ]; - /** @var $customer \Magento\Customer\Model\Customer|MockObject */ - $customer = $this->_objectManager->getObject(\Magento\Customer\Model\Customer::class, $arguments); - - foreach ($callbacks as $callback) { - call_user_func($callback, $customer); - } - } - /** * Test for method exportItem() * From 826b697e7049701cd825e88efeb39c31c40b09ec Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Tue, 22 Dec 2020 16:06:02 +0200 Subject: [PATCH 310/346] MC-39037: Report tabs are not aligned and not able to view properly --- .../Block/Widget/Grid/ExtendedTest.php | 56 ++++++++++++++++--- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ExtendedTest.php b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ExtendedTest.php index 328a85ffd51ad..6d3761fdfcb79 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ExtendedTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Block/Widget/Grid/ExtendedTest.php @@ -5,34 +5,44 @@ */ namespace Magento\Backend\Block\Widget\Grid; +use Laminas\Stdlib\Parameters; +use Magento\Backend\Block\Template\Context; +use Magento\Framework\Data\Collection; +use Magento\Framework\View\LayoutInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + /** * @magentoAppArea adminhtml */ -class ExtendedTest extends \PHPUnit\Framework\TestCase +class ExtendedTest extends TestCase { /** - * @var \Magento\Backend\Block\Widget\Grid\Extended + * @var Extended */ protected $_block; /** - * @var \Magento\Framework\View\LayoutInterface + * @var LayoutInterface */ protected $_layoutMock; + /** + * @inheritDoc + */ protected function setUp(): void { parent::setUp(); - $this->_layoutMock = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\View\LayoutInterface::class + $this->_layoutMock = Bootstrap::getObjectManager()->get( + LayoutInterface::class ); - $context = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Backend\Block\Template\Context::class, + $context = Bootstrap::getObjectManager()->create( + Context::class, ['layout' => $this->_layoutMock] ); $this->_block = $this->_layoutMock->createBlock( - \Magento\Backend\Block\Widget\Grid\Extended::class, + Extended::class, 'grid', ['context' => $context] ); @@ -47,7 +57,7 @@ protected function setUp(): void public function testAddColumnAddsChildToColumnSet() { $this->assertInstanceOf( - \Magento\Backend\Block\Widget\Grid\Column::class, + Column::class, $this->_block->getColumnSet()->getChildBlock('column1') ); $this->assertCount(2, $this->_block->getColumnSet()->getChildNames()); @@ -84,4 +94,32 @@ public function testGetMainButtonsHtmlReturnsEmptyStringIfFiltersArentVisible() $this->_block->setFilterVisibility(false); $this->assertEquals('', $this->_block->getMainButtonsHtml()); } + + /** + * Checks that template does not have redundant div close tag + * + * @return void + */ + public function testExtendedTemplateMarkup(): void + { + $mockCollection = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->_block->setCollection($mockCollection); + $this->_block->getRequest() + ->setQuery( + Bootstrap::getObjectManager() + ->create( + Parameters::class, + [ + 'values' => [ + 'ajax' => true + ] + ] + ) + ); + $html = $this->_block->getHtml(); + $html = str_replace(["\n", " "], '', $html); + $this->assertStringEndsWith("</table></div>", $html); + } } From 8e74c61c8ccb10779fd6c307cd9b0e47bbd14294 Mon Sep 17 00:00:00 2001 From: engcom-Kilo <mikola.malevanec@transoftgroup.com> Date: Tue, 22 Dec 2020 18:30:58 +0200 Subject: [PATCH 311/346] MC-39609: Product import: Only the first additional image is validated. --- .../Model/Import/Product/Validator/Media.php | 2 +- .../Model/Import/ProductTest.php | 21 +++++++++++++++++++ .../Model/Import/_files/import_media.csv | 2 +- ...port_media_additional_images_storeview.csv | 2 +- ...media_additional_images_with_wrong_url.csv | 2 ++ .../_files/import_media_existing_images.csv | 2 +- .../_files/import_media_hidden_images.csv | 4 ++-- ...ucts_to_import_with_non_existing_image.csv | 2 +- 8 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_with_wrong_url.csv diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php index d1fe1eee80e19..8df5afce568f1 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product/Validator/Media.php @@ -114,8 +114,8 @@ public function isValid($value) ] ); $valid = false; + break; } - break; } } return $valid; diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 3ca6754c77767..dfb57d91a7cc6 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -3415,4 +3415,25 @@ public function importImagesDataProvider(): array ] ]; } + + /** + * Verify additional images url validation during import. + * + * @magentoDbIsolation enabled + * @return void + */ + public function testImportInvalidAdditionalImages(): void + { + $pathToFile = __DIR__ . '/_files/import_media_additional_images_with_wrong_url.csv'; + $filesystem = BootstrapHelper::getObjectManager()->create(Filesystem::class); + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + $source = $this->objectManager->create(Csv::class, ['file' => $pathToFile, 'directory' => $directory]); + $errors = $this->_model->setSource($source)->setParameters(['behavior' => Import::BEHAVIOR_APPEND]) + ->validateData(); + $this->assertEquals($errors->getErrorsCount(), 1); + $this->assertEquals( + "Wrong URL/path used for attribute additional_images", + $errors->getErrorByRowNumber(0)[0]->getErrorMessage() + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media.csv index a3e8f8e47ab08..3478512e25028 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media.csv +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media.csv @@ -1,2 +1,2 @@ sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus -simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,, +simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg,magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,, diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv index ed8755a73fcb1..4d2e7234c9362 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_storeview.csv @@ -1,2 +1,2 @@ "sku","store_view_code","additional_images","additional_image_labels" -"simple","fixturestore","magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two" +"simple","fixturestore","magento_additional_image_one.jpg,magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two" diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_with_wrong_url.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_with_wrong_url.csv new file mode 100644 index 0000000000000..c2b9e4f6fa936 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_additional_images_with_wrong_url.csv @@ -0,0 +1,2 @@ +sku,product_type,name,price,attribute_set_code,additional_images +simple1,simple,"simple 1",25,Default,"additional_image_one.jpg,additional_image with spaces.jpg" diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_existing_images.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_existing_images.csv index a3e8f8e47ab08..3478512e25028 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_existing_images.csv +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_existing_images.csv @@ -1,2 +1,2 @@ sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus -simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,, +simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg,magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,, diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_hidden_images.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_hidden_images.csv index 1c1bebee57578..f54d4b7f401d4 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_hidden_images.csv +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_hidden_images.csv @@ -1,2 +1,2 @@ -sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus -simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product,magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/2015 7:05,10/20/2015 7:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two","magento_image.jpg,magento_thumbnail.jpg,magento_additional_image_two.jpg",,,,,,, +sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus +simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product,magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/2015 7:05,10/20/2015 7:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg,magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two","magento_image.jpg,magento_thumbnail.jpg,magento_additional_image_two.jpg",,,,,,, diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_non_existing_image.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_non_existing_image.csv index 8122433a8c9e1..6037ee008a8ec 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_non_existing_image.csv +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/products_to_import_with_non_existing_image.csv @@ -1,2 +1,2 @@ sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus -simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,/no/exists/image/magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,, +simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product ,/no/exists/image/magento_image.jpg,Image Label,magento_small_image.jpg,Small Image Label,magento_thumbnail.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg,magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,, From 1093ad0421851caad9bf361269aadccd7997667f Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 23 Dec 2020 11:29:33 +0200 Subject: [PATCH 312/346] MC-39852: Change customer custom address file attribute editor on backend to don't use direct link for preview --- .../Controller/Adminhtml/Address/Viewfile.php | 180 ++++++++++++++++++ .../Magento/Customer/Model/FileProcessor.php | 7 +- .../Test/Unit/Model/FileProcessorTest.php | 22 +-- pub/media/customer_address/.htaccess | 7 + 4 files changed, 202 insertions(+), 14 deletions(-) create mode 100644 app/code/Magento/Customer/Controller/Adminhtml/Address/Viewfile.php create mode 100644 pub/media/customer_address/.htaccess diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Address/Viewfile.php b/app/code/Magento/Customer/Controller/Adminhtml/Address/Viewfile.php new file mode 100644 index 0000000000000..a8cad14c23a72 --- /dev/null +++ b/app/code/Magento/Customer/Controller/Adminhtml/Address/Viewfile.php @@ -0,0 +1,180 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Controller\Adminhtml\Address; + +use Magento\Customer\Api\AddressMetadataInterface; +use Magento\Framework\Exception\NotFoundException; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Controller\Result\RawFactory; +use Magento\Framework\Url\DecoderInterface; +use Magento\Framework\Controller\ResultInterface; +use Magento\Framework\Filesystem; +use Magento\Framework\Controller\Result\Raw; +use Magento\MediaStorage\Helper\File\Storage; +use Magento\Framework\App\Response\Http\FileFactory; +use Magento\Framework\Filesystem\Io\File as IoFile; +use Magento\Backend\App\Action\Context; +use Magento\Framework\App\Action\HttpGetActionInterface; +use Magento\Backend\App\Action; + +/** + * Class Viewfile serves to show file or image by file/image name provided in request parameters. + */ +class Viewfile extends Action implements HttpGetActionInterface +{ + /** + * Authorization level of a basic admin session + */ + const ADMIN_RESOURCE = 'Magento_Customer::manage'; + + /** + * @var RawFactory + */ + private $resultRawFactory; + + /** + * @var DecoderInterface + */ + private $urlDecoder; + + /** + * @var Filesystem + */ + private $filesystem; + + /** + * @var Storage + */ + private $storage; + + /** + * @var FileFactory + */ + private $fileFactory; + + /** + * @var IoFile + */ + private $ioFile; + + /** + * @param Context $context + * @param FileFactory $fileFactory + * @param RawFactory $resultRawFactory + * @param DecoderInterface $urlDecoder + * @param Filesystem $filesystem + * @param Storage $storage + * @param IoFile $ioFile + */ + public function __construct( + Context $context, + FileFactory $fileFactory, + RawFactory $resultRawFactory, + DecoderInterface $urlDecoder, + Filesystem $filesystem, + Storage $storage, + IoFile $ioFile + ) { + parent::__construct($context); + $this->resultRawFactory = $resultRawFactory; + $this->urlDecoder = $urlDecoder; + $this->filesystem = $filesystem; + $this->storage = $storage; + $this->fileFactory = $fileFactory; + $this->ioFile = $ioFile; + } + + /** + * Customer address view file action + * + * @return ResultInterface|void + * @throws NotFoundException + */ + public function execute() + { + list($file, $plain) = $this->getFileParams(); + + $directory = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA); + $fileName = AddressMetadataInterface::ENTITY_TYPE_ADDRESS . DIRECTORY_SEPARATOR . + ltrim($file, DIRECTORY_SEPARATOR); + $path = $directory->getAbsolutePath($fileName); + if (mb_strpos($path, '..') !== false + || (!$directory->isFile($fileName) && !$this->storage->processStorageFile($path)) + ) { + throw new NotFoundException(__('Page not found.')); + } + + $pathInfo = $this->ioFile->getPathInfo($path); + if ($plain) { + $extension = $pathInfo['extension']; + switch (strtolower($extension)) { + case 'gif': + $contentType = 'image/gif'; + break; + case 'jpg': + $contentType = 'image/jpeg'; + break; + case 'png': + $contentType = 'image/png'; + break; + default: + $contentType = 'application/octet-stream'; + break; + } + $stat = $directory->stat($fileName); + $contentLength = $stat['size']; + $contentModify = $stat['mtime']; + + /** @var Raw $resultRaw */ + $resultRaw = $this->resultRawFactory->create(); + $resultRaw->setHttpResponseCode(200) + ->setHeader('Pragma', 'public', true) + ->setHeader('Content-type', $contentType, true) + ->setHeader('Content-Length', $contentLength) + ->setHeader('Last-Modified', date('r', $contentModify)); + $resultRaw->setContents($directory->readFile($fileName)); + + return $resultRaw; + } else { + $name = $pathInfo['basename']; + $this->fileFactory->create( + $name, + ['type' => 'filename', 'value' => $fileName], + DirectoryList::MEDIA + ); + } + } + + /** + * Get parameters from request. + * + * @return array + * @throws NotFoundException + */ + private function getFileParams() : array + { + $file = null; + $plain = false; + if ($this->getRequest()->getParam('file')) { + // download file + $file = $this->urlDecoder->decode( + $this->getRequest()->getParam('file') + ); + } elseif ($this->getRequest()->getParam('image')) { + // show plain image + $file = $this->urlDecoder->decode( + $this->getRequest()->getParam('image') + ); + $plain = true; + } else { + throw new NotFoundException(__('Page not found.')); + } + + return [$file, $plain]; + } +} diff --git a/app/code/Magento/Customer/Model/FileProcessor.php b/app/code/Magento/Customer/Model/FileProcessor.php index 02bfe78be535c..59e2d5fb2b577 100644 --- a/app/code/Magento/Customer/Model/FileProcessor.php +++ b/app/code/Magento/Customer/Model/FileProcessor.php @@ -158,9 +158,10 @@ public function getViewUrl($filePath, $type) $viewUrl = ''; if ($this->entityTypeCode == AddressMetadataInterface::ENTITY_TYPE_ADDRESS) { - $filePath = $this->entityTypeCode . '/' . ltrim($filePath, '/'); - $viewUrl = $this->urlBuilder->getBaseUrl(['_type' => UrlInterface::URL_TYPE_MEDIA]) - . $this->mediaDirectory->getRelativePath($filePath); + $viewUrl = $this->urlBuilder->getUrl( + 'customer/address/viewfile', + [$type => $this->urlEncoder->encode(ltrim($filePath, '/'))] + ); } if ($this->entityTypeCode == CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER) { diff --git a/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php b/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php index 7a0522f6476f2..fb775ce78bbbc 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/FileProcessorTest.php @@ -162,22 +162,22 @@ public function testGetViewUrlCustomer() public function testGetViewUrlCustomerAddress() { $filePath = 'filename.ext1'; + $encodedFilePath = 'encodedfilenameext1'; - $baseUrl = 'baseUrl'; - $relativeUrl = 'relativeUrl'; + $fileUrl = 'fileUrl'; - $this->urlBuilder->expects($this->once()) - ->method('getBaseUrl') - ->with(['_type' => UrlInterface::URL_TYPE_MEDIA]) - ->willReturn($baseUrl); + $this->urlEncoder->expects($this->once()) + ->method('encode') + ->with($filePath) + ->willReturn($encodedFilePath); - $this->mediaDirectory->expects($this->once()) - ->method('getRelativePath') - ->with(AddressMetadataInterface::ENTITY_TYPE_ADDRESS . '/' . $filePath) - ->willReturn($relativeUrl); + $this->urlBuilder->expects($this->once()) + ->method('getUrl') + ->with('customer/address/viewfile', ['image' => $encodedFilePath]) + ->willReturn($fileUrl); $model = $this->getModel(AddressMetadataInterface::ENTITY_TYPE_ADDRESS); - $this->assertEquals($baseUrl . $relativeUrl, $model->getViewUrl($filePath, 'image')); + $this->assertEquals($fileUrl, $model->getViewUrl($filePath, 'image')); } public function testRemoveUploadedFile() diff --git a/pub/media/customer_address/.htaccess b/pub/media/customer_address/.htaccess new file mode 100644 index 0000000000000..b97408bad3f2e --- /dev/null +++ b/pub/media/customer_address/.htaccess @@ -0,0 +1,7 @@ +<IfVersion < 2.4> + order allow,deny + deny from all +</IfVersion> +<IfVersion >= 2.4> + Require all denied +</IfVersion> From 22ca921b91527ff3a200a4126dd7ddb0bae93c38 Mon Sep 17 00:00:00 2001 From: Anna Pak <a.pak@atwix.com> Date: Wed, 23 Dec 2020 13:26:19 +0200 Subject: [PATCH 313/346] updated with StorefrontHoverProductOnCategoryPageActionGroup --- .../Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml | 2 +- ...essStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml | 2 +- .../AddressStateFieldShouldNotAcceptJustIntegerValuesTest.xml | 2 +- .../NoErrorCartCheckoutForProductsDeletedFromMiniCartTest.xml | 2 +- ...stomerCheckoutTestWithMultipleAddressesAndTaxRatesTest.xml | 4 ++-- ...tomerCheckoutTestWithRestrictedCountriesForPaymentTest.xml | 2 +- .../StorefrontGuestCheckoutTest.xml | 2 +- ...GuestCheckoutTestWithRestrictedCountriesForPaymentTest.xml | 2 +- .../Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml | 2 +- .../StorefrontVerifySecureURLRedirectMultishippingTest.xml | 2 +- .../Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml | 2 +- .../Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml | 3 +-- 12 files changed, 13 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml index 88fc5b7171592..e08982a266ee5 100644 --- a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml +++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontGoToDetailsPageWhenAddingToCartTest.xml @@ -70,7 +70,7 @@ <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory"/> <!--Click add to cart--> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addProductToCart"/> <!--Check for details page--> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml index f578a9c02caca..f43211e909cca 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldForUKCustomerRemainOptionAfterRefreshTest.xml @@ -34,7 +34,7 @@ <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldShouldNotAcceptJustIntegerValuesTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldShouldNotAcceptJustIntegerValuesTest.xml index 7c4b18e1aab89..b825757636c0b 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldShouldNotAcceptJustIntegerValuesTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/AddressStateFieldShouldNotAcceptJustIntegerValuesTest.xml @@ -37,7 +37,7 @@ <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/NoErrorCartCheckoutForProductsDeletedFromMiniCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/NoErrorCartCheckoutForProductsDeletedFromMiniCartTest.xml index bf942e70cfa36..d269a666d975e 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/NoErrorCartCheckoutForProductsDeletedFromMiniCartTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/NoErrorCartCheckoutForProductsDeletedFromMiniCartTest.xml @@ -39,7 +39,7 @@ </after> <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onStorefrontCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addProductToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createSimpleProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithMultipleAddressesAndTaxRatesTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithMultipleAddressesAndTaxRatesTest.xml index 9747980801068..396ba5894aeb3 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithMultipleAddressesAndTaxRatesTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithMultipleAddressesAndTaxRatesTest.xml @@ -82,7 +82,7 @@ <amOnPage url="{{StorefrontCategoryPage.url($$simplecategory.name$$)}}" stepKey="onCategoryPage1"/> <waitForPageLoad stepKey="waitForCatalogPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct1"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct1"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart1"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded1"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$simpleproduct1.name$$ to your shopping cart." stepKey="seeAddedToCartMessage1"/> @@ -101,7 +101,7 @@ <amOnPage url="{{StorefrontCategoryPage.url($$simplecategory.name$$)}}" stepKey="onCategoryPage2"/> <waitForPageLoad stepKey="waitForCatalogPageLoad2"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct2"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct2"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart2"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded2"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$simpleproduct1.name$$ to your shopping cart." stepKey="seeAddedToCartMessage2"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithRestrictedCountriesForPaymentTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithRestrictedCountriesForPaymentTest.xml index d6f1408c2b66a..8325eeb0da7e3 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithRestrictedCountriesForPaymentTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerCheckoutTest/StorefrontCustomerCheckoutTestWithRestrictedCountriesForPaymentTest.xml @@ -51,7 +51,7 @@ <!-- Add product to cart --> <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTest.xml index b591aefbdc889..4c9828d17ca1a 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTest.xml @@ -39,7 +39,7 @@ <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTestWithRestrictedCountriesForPaymentTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTestWithRestrictedCountriesForPaymentTest.xml index 15b550657ef60..7090b0d4fd3fd 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTestWithRestrictedCountriesForPaymentTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutTest/StorefrontGuestCheckoutTestWithRestrictedCountriesForPaymentTest.xml @@ -42,7 +42,7 @@ <!-- Add product to cart --> <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml index 03323b7b9c855..7465ab6aa69e4 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml @@ -27,7 +27,7 @@ </createData> <amOnPage url="{{StorefrontCategoryPage.url($$category.name$$)}}" stepKey="goToCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="moveMouseOverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="moveMouseOverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="clickAddToCartButton"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForAddedToCartSuccessMessage"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$product.name$$ to your shopping cart." stepKey="seeAddedToCartSuccessMessage"/> diff --git a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontVerifySecureURLRedirectMultishippingTest.xml b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontVerifySecureURLRedirectMultishippingTest.xml index fe33078755ac4..515c9b2102f5e 100644 --- a/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontVerifySecureURLRedirectMultishippingTest.xml +++ b/app/code/Magento/Multishipping/Test/Mftf/Test/StorefrontVerifySecureURLRedirectMultishippingTest.xml @@ -32,7 +32,7 @@ </actionGroup> <amOnPage url="{{StorefrontCategoryPage.url($$category.name$$)}}" stepKey="goToCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="moveMouseOverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="moveMouseOverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="clickAddToCartButton"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForAddedToCartSuccessMessage"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$product.name$$ to your shopping cart." stepKey="seeAddedToCartSuccessMessage"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml index 91a8f95880fbc..d5128dc3f8b0c 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateInvoiceTest.xml @@ -33,7 +33,7 @@ <!-- todo: Create an order via the api instead of driving the browser --> <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <actionGroup ref="StorefrontClickOnMiniCartActionGroup" stepKey="clickCart"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml index b2bdf8ce5d90b..16b20abc0a583 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml @@ -62,7 +62,7 @@ <!-- Place an order from Storefront as a Guest --> <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverOverProduct"/> + <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductToAdd"/> <actionGroup ref="StorefrontClickOnMiniCartActionGroup" stepKey="clickCart"/> @@ -149,4 +149,3 @@ </assertEquals> </test> </tests> - From 275e42e42a51f3c04b2dafd4d17a8245e1a036cf Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Wed, 23 Dec 2020 13:39:28 +0200 Subject: [PATCH 314/346] MC-37385: Unexpected unchecking of "Append Comments" check-box --- .../Magento/Sales/Model/AdminOrder/Create.php | 7 ++-- .../Adminhtml/Order/Create/LoadBlockTest.php | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 5d621f1632837..a0e0dd9aeb2bd 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -1716,10 +1716,9 @@ public function importPostData($data) if (isset($data['comment'])) { $this->getQuote()->addData($data['comment']); - if (empty($data['comment']['customer_note_notify'])) { - $this->getQuote()->setCustomerNoteNotify(false); - } else { - $this->getQuote()->setCustomerNoteNotify(true); + if ($this->getIsValidate()) { + $notify = !empty($data['comment']['customer_note_notify']); + $this->getQuote()->setCustomerNoteNotify($notify); } } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php index 529b491269643..3567a7e00764f 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/LoadBlockTest.php @@ -231,6 +231,40 @@ public function testAddProductToOrderFromWishList(): void $this->assertCount(1, $quoteItems); } + /** + * Check that customer notification is NOT disabled after comment is updated. + * + * @return void + * @magentoDataFixture Magento/Checkout/_files/quote_with_customer_without_address.php + */ + public function testUpdateCustomerNote(): void + { + $customerNote = 'Example Comment'; + $quoteId = $this->getQuoteByReservedOrderId->execute('test_order_with_customer_without_address')->getId(); + $this->session->setQuoteId($quoteId); + $params = [ + 'json' => false, + 'block' => 'totals', + 'as_js_varname' => false, + ]; + $post = $this->hydratePost([ + 'order' => [ + 'comment' => [ + CartInterface::KEY_CUSTOMER_NOTE => $customerNote + ], + ], + ]); + $this->dispatchWitParams($params, $post); + + $quote = $this->session->getQuote(); + $this->assertEquals($customerNote, $quote->getCustomerNote()); + $this->assertTrue((bool)$quote->getCustomerNoteNotify()); + + preg_match('/id="notify_customer"(?<attributes>.*?)\/>/s', $this->getResponse()->getBody(), $matches); + $this->assertArrayHasKey('attributes', $matches); + $this->assertStringContainsString('checked="checked"', $matches['attributes']); + } + /** * Check customer quotes * From 08a6b9cb5fdd08b0813936d0e0309219c11e3c84 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Wed, 23 Dec 2020 15:21:34 +0200 Subject: [PATCH 315/346] MC-39864: [Magento Cloud] - Tax Miscalculation --- .../Model/Order/Creditmemo/Total/Tax.php | 69 +++++++++++++++++-- .../Model/ResourceModel/Order/Invoice.php | 35 ++++++++-- 2 files changed, 92 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index eba84dcfb6364..faed11c4f718e 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -5,13 +5,31 @@ */ namespace Magento\Sales\Model\Order\Creditmemo\Total; +use Magento\Sales\Api\Data\CreditmemoInterface; use Magento\Sales\Model\Order\Creditmemo; +use Magento\Sales\Model\Order\Invoice; +use Magento\Sales\Model\ResourceModel\Order\Invoice as ResourceInvoice; /** * Collects credit memo taxes. */ class Tax extends AbstractTotal { + /** + * @var ResourceInvoice + */ + private $resourceInvoice; + + /** + * @param ResourceInvoice $resourceInvoice + * @param array $data + */ + public function __construct(ResourceInvoice $resourceInvoice, array $data = []) + { + $this->resourceInvoice = $resourceInvoice; + parent::__construct($data); + } + /** * {@inheritdoc} * @SuppressWarnings(PHPMD.NPathComplexity) @@ -182,8 +200,12 @@ private function calculateAllowedTax(Creditmemo $creditMemo): float { $invoice = $creditMemo->getInvoice(); $order = $creditMemo->getOrder(); - $amount = $invoice !== null ? $invoice->getTaxAmount() - : $order->getTaxInvoiced() - $order->getTaxRefunded(); + if ($invoice!== null) { + $amount = $invoice->getTaxAmount() + - $this->calculateInvoiceRefundedAmount($invoice, CreditmemoInterface::TAX_AMOUNT); + } else { + $amount = $order->getTaxInvoiced() - $order->getTaxRefunded(); + } return (float) $amount - $creditMemo->getTaxAmount(); } @@ -198,8 +220,13 @@ private function calculateAllowedBaseTax(Creditmemo $creditMemo): float { $invoice = $creditMemo->getInvoice(); $order = $creditMemo->getOrder(); - $amount = $invoice !== null ? $invoice->getBaseTaxAmount() - : $order->getBaseTaxInvoiced() - $order->getBaseTaxRefunded(); + + if ($invoice!== null) { + $amount = $invoice->getBaseTaxAmount() + - $this->calculateInvoiceRefundedAmount($invoice, CreditmemoInterface::BASE_TAX_AMOUNT); + } else { + $amount = $order->getBaseTaxInvoiced() - $order->getBaseTaxRefunded(); + } return (float) $amount - $creditMemo->getBaseTaxAmount(); } @@ -217,7 +244,14 @@ private function calculateAllowedDiscountTaxCompensation(Creditmemo $creditMemo) if ($invoice) { $amount = $invoice->getDiscountTaxCompensationAmount() - + $invoice->getShippingDiscountTaxCompensationAmount(); + + $invoice->getShippingDiscountTaxCompensationAmount() + - $this->calculateInvoiceRefundedAmount( + $invoice, + CreditmemoInterface::DISCOUNT_TAX_COMPENSATION_AMOUNT + ) - $this->calculateInvoiceRefundedAmount( + $invoice, + CreditmemoInterface::SHIPPING_DISCOUNT_TAX_COMPENSATION_AMOUNT + ); } else { $amount = $order->getDiscountTaxCompensationInvoiced() + $order->getShippingDiscountTaxCompensationAmount() @@ -243,7 +277,14 @@ private function calculateAllowedBaseDiscountTaxCompensation(Creditmemo $creditM if ($invoice) { $amount = $invoice->getBaseDiscountTaxCompensationAmount() - + $invoice->getBaseShippingDiscountTaxCompensationAmnt(); + + $invoice->getBaseShippingDiscountTaxCompensationAmnt() + - $this->calculateInvoiceRefundedAmount( + $invoice, + CreditmemoInterface::BASE_DISCOUNT_TAX_COMPENSATION_AMOUNT + ) - $this->calculateInvoiceRefundedAmount( + $invoice, + CreditmemoInterface::BASE_SHIPPING_DISCOUNT_TAX_COMPENSATION_AMNT + ); } else { $amount = $order->getBaseDiscountTaxCompensationInvoiced() + $order->getBaseShippingDiscountTaxCompensationAmnt() @@ -255,4 +296,20 @@ private function calculateAllowedBaseDiscountTaxCompensation(Creditmemo $creditM - $creditMemo->getBaseShippingDiscountTaxCompensationAmnt() - $creditMemo->getBaseDiscountTaxCompensationAmount(); } + + /** + * Calculate refunded amount for invoice + * + * @param Invoice $invoice + * @param string $field + * @return float + */ + private function calculateInvoiceRefundedAmount(Invoice $invoice, string $field): float + { + if (empty($invoice->getId())) { + return 0; + } + + return $this->resourceInvoice->calculateRefundedAmount((int)$invoice->getId(), $field); + } } diff --git a/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice.php b/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice.php index 848f88118ed32..bc21e9cd6c894 100644 --- a/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice.php +++ b/app/code/Magento/Sales/Model/ResourceModel/Order/Invoice.php @@ -5,11 +5,9 @@ */ namespace Magento\Sales\Model\ResourceModel\Order; -use Magento\Framework\App\ResourceConnection; -use Magento\SalesSequence\Model\Manager; -use Magento\Sales\Model\ResourceModel\Attribute; +use Magento\Framework\DataObject; +use Magento\Framework\Model\AbstractModel; use Magento\Sales\Model\ResourceModel\EntityAbstract as SalesResource; -use Magento\Framework\Model\ResourceModel\Db\VersionControl\Snapshot; use Magento\Sales\Model\Spi\InvoiceResourceInterface; /** @@ -37,10 +35,10 @@ protected function _construct() /** * Perform actions before object save * - * @param \Magento\Framework\Model\AbstractModel|\Magento\Framework\DataObject $object + * @param AbstractModel|DataObject $object * @return $this */ - protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object) + protected function _beforeSave(AbstractModel $object) { /** @var \Magento\Sales\Model\Order\Invoice $object */ if (!$object->getOrderId() && $object->getOrder()) { @@ -50,4 +48,29 @@ protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object) return parent::_beforeSave($object); } + + /** + * Calculate refunded amount for invoice + * + * @param int $invoiceId + * @param string $filed + * @return float + * @throws \InvalidArgumentException + */ + public function calculateRefundedAmount(int $invoiceId, string $filed): float + { + if (empty($filed)) { + throw new \InvalidArgumentException('The field param must be passed'); + } + + $select = $this->getConnection()->select(); + $select->from( + ['credit_memo' => $this->getTable('sales_creditmemo')], + ['total' => new \Zend_Db_Expr("SUM(credit_memo.{$filed})")] + )->where( + "credit_memo.invoice_id = ?", $invoiceId + ); + + return (float) $this->getConnection()->fetchOne($select); + } } From a6099456094105c04b415482d7836ba726000bdb Mon Sep 17 00:00:00 2001 From: Kate Kyzyma <kate@atwix.com> Date: Wed, 23 Dec 2020 16:47:45 +0200 Subject: [PATCH 316/346] Refactoring the test --- ...oductPriceWithDisabledChildProductTest.xml | 104 +++++++++++++----- 1 file changed, 75 insertions(+), 29 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWithDisabledChildProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWithDisabledChildProductTest.xml index a72af673c009a..f2413a1523394 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWithDisabledChildProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminCheckConfigurableProductPriceWithDisabledChildProductTest.xml @@ -124,62 +124,108 @@ </after> <!-- Open Product in Store Front Page --> - <amOnPage url="$$createConfigProduct.sku$$.html" stepKey="openProductInStoreFront"/> - <waitForPageLoad stepKey="waitForProductToLoad"/> + <actionGroup ref="StorefrontOpenProductEntityPageActionGroup" stepKey="openProductInStoreFront"> + <argument name="product" value="$createConfigProduct$"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForProductToLoad"/> <!-- Verify category,Configurable product and initial price --> - <seeElement selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="seeCategoryInFrontPage"/> - <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="$$createConfigProduct.name$$" stepKey="seeProductNameInStoreFront"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="$$createConfigChildProduct1.price$$" stepKey="seeInitialPriceInStoreFront"/> + <actionGroup ref="StorefrontAssertCategoryNameIsShownInMenuActionGroup" stepKey="seeCategoryInFrontPage"> + <argument name="categoryName" value="$$createCategory.name$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductNameOnProductPageActionGroup" stepKey="seeProductNameInStoreFront"> + <argument name="productName" value="$$createConfigProduct.name$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeInitialPriceInStoreFront"> + <argument name="productPrice" value="$$createConfigChildProduct1.price$$"/> + </actionGroup> <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeProductSkuInStoreFront"> <argument name="productSku" value="$$createConfigProduct.sku$$"/> </actionGroup> - <see selector="{{StorefrontProductInfoMainSection.productStockStatus}}" userInput="In Stock" stepKey="seeProductStatusInStoreFront"/> + <actionGroup ref="AssertStorefrontProductStockStatusOnProductPageActionGroup" stepKey="seeProductStatusInStoreFront"> + <argument name="productStockStatus" value="In Stock"/> + </actionGroup> <!-- Verify First Child Product attribute option is displayed --> <see selector="{{StorefrontProductInfoMainSection.productOptionSelect($$createConfigProductAttribute.default_value$$)}}" userInput="$$getConfigAttributeOption1.label$$" stepKey="seeOption1"/> <!-- Select product Attribute option1, option2 and option3 and verify changes in the price --> - <selectOption selector="{{StorefrontProductInfoMainSection.productOptionSelect($$createConfigProductAttribute.default_value$$)}}" userInput="$$getConfigAttributeOption1.label$$" stepKey="selectOption1"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="$$createConfigChildProduct1.price$$" stepKey="seeChildProduct1PriceInStoreFront"/> - <selectOption selector="{{StorefrontProductInfoMainSection.productOptionSelect($$createConfigProductAttribute.default_value$$)}}" userInput="$$getConfigAttributeOption2.label$$" stepKey="selectOption2"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="$$createConfigChildProduct2.price$$" stepKey="seeChildProduct2PriceInStoreFront"/> - <selectOption selector="{{StorefrontProductInfoMainSection.productOptionSelect($$createConfigProductAttribute.default_value$$)}}" userInput="$$getConfigAttributeOption3.label$$" stepKey="selectOption3"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="$$createConfigChildProduct3.price$$" stepKey="seeChildProduct3PriceInStoreFront"/> - + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectOption1"> + <argument name="attributeLabel" value="$$createConfigProductAttribute.default_value$$"/> + <argument name="optionLabel" value="$$getConfigAttributeOption1.label$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeChildProduct1PriceInStoreFront"> + <argument name="productPrice" value="$$createConfigChildProduct1.price$$"/> + </actionGroup> + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectOption2"> + <argument name="attributeLabel" value="$$createConfigProductAttribute.default_value$$"/> + <argument name="optionLabel" value="$$getConfigAttributeOption2.label$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeChildProduct2PriceInStoreFront"> + <argument name="productPrice" value="$$createConfigChildProduct2.price$$"/> + </actionGroup> + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectOption3"> + <argument name="attributeLabel" value="$$createConfigProductAttribute.default_value$$"/> + <argument name="optionLabel" value="$$getConfigAttributeOption3.label$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeChildProduct3PriceInStoreFront"> + <argument name="productPrice" value="$$createConfigChildProduct3.price$$"/> + </actionGroup> <!-- Open Product Index Page and Filter First Child product --> - <actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndex"/> - <actionGroup ref="FilterProductGridBySkuActionGroup" stepKey="filterProduct"> - <argument name="product" value="ApiSimpleOne"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="navigateToProductIndex"/> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="filterProduct"/> + <actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="selectFirstRow"> + <argument name="productId" value="$$createConfigChildProduct1.id$$"/> </actionGroup> - <click selector="{{AdminProductGridFilterSection.nthRow('1')}}" stepKey="selectFirstRow"/> <waitForPageLoad stepKey="waitForProductPageToLoad"/> <!-- Disable the product --> - <click selector="{{AdminProductFormSection.enableProductLabel}}" stepKey="disableProduct"/> + <actionGroup ref="ToggleProductEnabledActionGroup" stepKey="disableProduct"/> <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="clickOnSaveButton"/> - <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You saved the product." stepKey="messageYouSavedTheProductIsShown"/> + <actionGroup ref="AssertMessageInAdminPanelActionGroup" stepKey="messageYouSavedTheProductIsShown"> + <argument name="message" value="You saved the product."/> + </actionGroup> <!-- Open Product Store Front Page --> - <amOnPage url="$$createConfigProduct.sku$$.html" stepKey="openProductInStoreFront1"/> - <waitForPageLoad stepKey="waitForProductToLoad1"/> + <actionGroup ref="StorefrontOpenProductEntityPageActionGroup" stepKey="openProductInStoreFront1"> + <argument name="product" value="$createConfigProduct$"/> + </actionGroup> + <comment userInput="Comment is added to preserve the step key for backward compatibility" stepKey="waitForProductToLoad1"/> <!-- Verify category,configurable product and updated price --> - <seeElement selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="seeCategoryInFrontPage1"/> - <see selector="{{StorefrontProductInfoMainSection.productName}}" userInput="$$createConfigProduct.name$$" stepKey="seeProductNameInStoreFront1"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="$$createConfigChildProduct2.price$$" stepKey="seeUpdatedProductPriceInStoreFront"/> + <actionGroup ref="StorefrontAssertCategoryNameIsShownInMenuActionGroup" stepKey="seeCategoryInFrontPage1"> + <argument name="categoryName" value="$$createCategory.name$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductNameOnProductPageActionGroup" stepKey="seeProductNameInStoreFront1"> + <argument name="productName" value="$$createConfigProduct.name$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeUpdatedProductPriceInStoreFront"> + <argument name="productPrice" value="$$createConfigChildProduct2.price$$"/> + </actionGroup> <actionGroup ref="StorefrontAssertProductSkuOnProductPageActionGroup" stepKey="seeProductSkuInStoreFront1"> <argument name="productSku" value="$$createConfigProduct.sku$$"/> </actionGroup> - <see selector="{{StorefrontProductInfoMainSection.productStockStatus}}" userInput="In Stock" stepKey="seeProductStatusInStoreFront1"/> + <actionGroup ref="AssertStorefrontProductStockStatusOnProductPageActionGroup" stepKey="seeProductStatusInStoreFront1"> + <argument name="productStockStatus" value="In Stock"/> + </actionGroup> <!-- Verify product Attribute Option1 is not displayed --> <dontSee selector="{{StorefrontProductInfoMainSection.productOptionSelect($$createConfigProductAttribute.default_value$$)}}" userInput="$$getConfigAttributeOption1.label$$" stepKey="dontSeeOption1"/> <!--Select product Attribute option2 and option3 and verify changes in the price --> - <selectOption selector="{{StorefrontProductInfoMainSection.productOptionSelect($$createConfigProductAttribute.default_value$$)}}" userInput="$$getConfigAttributeOption2.label$$" stepKey="selectTheOption2"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="$$createConfigChildProduct2.price$$" stepKey="seeSecondChildProductPriceInStoreFront"/> - <selectOption selector="{{StorefrontProductInfoMainSection.productOptionSelect($$createConfigProductAttribute.default_value$$)}}" userInput="$$getConfigAttributeOption3.label$$" stepKey="selectTheOption3"/> - <see selector="{{StorefrontProductInfoMainSection.productPrice}}" userInput="$$createConfigChildProduct3.price$$" stepKey="seeThirdProductPriceInStoreFront"/> + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectTheOption2"> + <argument name="attributeLabel" value="$$createConfigProductAttribute.default_value$$"/> + <argument name="optionLabel" value="$$getConfigAttributeOption2.label$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeSecondChildProductPriceInStoreFront"> + <argument name="productPrice" value="$$createConfigChildProduct2.price$$"/> + </actionGroup> + <actionGroup ref="StorefrontProductPageSelectDropDownOptionValueActionGroup" stepKey="selectTheOption3"> + <argument name="attributeLabel" value="$$createConfigProductAttribute.default_value$$"/> + <argument name="optionLabel" value="$$getConfigAttributeOption3.label$$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertProductPriceOnProductPageActionGroup" stepKey="seeThirdProductPriceInStoreFront"> + <argument name="productPrice" value="$$createConfigChildProduct3.price$$"/> + </actionGroup> </test> </tests> From 64d2fb97a832593ff0efdd6e32c0770d73b68140 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 23 Dec 2020 21:26:43 +0200 Subject: [PATCH 317/346] MC-39600: Create automated test for: "Change category/product url rewrite suffix in configurations" --- .../Catalog/Url/Rewrite/SuffixTest.php | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php new file mode 100644 index 0000000000000..6553dffb04df6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php @@ -0,0 +1,287 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\System\Config\Backend\Catalog\Url\Rewrite; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator; +use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator; +use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator; +use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator; +use Magento\Framework\App\Cache\Type\Block; +use Magento\Framework\App\Cache\Type\Collection; +use Magento\Framework\App\Cache\TypeListInterface; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\ObjectManagerInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\UrlRewrite\Model\Storage\DbStorage; +use PHPUnit\Framework\TestCase; + +/** + * Class checks url suffix config save behaviour + * + * @see \Magento\Catalog\Model\System\Config\Backend\Catalog\Url\Rewrite\Suffix + * + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ +class SuffixTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Suffix */ + private $model; + + /** @var DbStorage */ + private $urlFinder; + + /** @var StoreManagerInterface */ + private $storeManager; + + /** @var TypeListInterface */ + private $typeList; + + /** @var ScopeConfigInterface */ + private $scopeConfig; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var int */ + private $defaultStoreId; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->model = $this->objectManager->get(Suffix::class); + $this->urlFinder = $this->objectManager->get(DbStorage::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->typeList = $this->objectManager->get(TypeListInterface::class); + $this->scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->defaultStoreId = (int)$this->storeManager->getStore('default')->getId(); + } + + /** + * @return void + */ + public function testSaveWithError(): void + { + $this->expectException(LocalizedException::class); + $this->expectErrorMessage((string)__('Anchor symbol (#) is not supported in url rewrite suffix.')); + $this->model->setValue('.html#'); + $this->model->beforeSave(); + } + + /** + * @dataProvider wrongValuesProvider + * + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @param array $data + * @return void + */ + public function testSaveWithWrongData(array $data): void + { + $productId = (int)$this->productRepository->get('simple2')->getId(); + $this->model->addData($data); + $this->model->afterSave(); + $this->assertRewrite( + $this->scopeConfig->getValue(ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX), + [ + 'entity_type' => ProductUrlRewriteGenerator::ENTITY_TYPE, + 'entity_id' => $productId, + 'store_id' => $this->defaultStoreId, + ] + ); + } + + /** + * @return array + */ + public function wrongValuesProvider(): array + { + return [ + 'with_wrong_path' => [ + ['path' => 'wrong_path', 'value' => 'some_test_value'], + ], + 'with_null_value' => [ + ['path' => ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX, 'value' => null], + ], + ]; + } + + /** + * @magentoDbIsolation disabled + * + * @magentoDataFixture Magento/Catalog/_files/product_multistore_different_short_description.php + * + * @return void + */ + public function testSaveInStoreScope(): void + { + $productId = $this->productRepository->get('simple-different-short-description')->getId(); + $newSuffix = 'some_test_value_for_store'; + $storeId = $this->storeManager->getStore('fixturestore')->getId(); + $this->model->addData([ + 'path' => ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX, + 'value' => $newSuffix, + 'scope' => ScopeInterface::SCOPE_STORES, + 'scope_id' => $storeId, + ]); + $this->model->afterSave(); + $this->assertRewrite( + $this->scopeConfig->getValue(ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX), + [ + 'entity_type' => ProductUrlRewriteGenerator::ENTITY_TYPE, + 'entity_id' => $productId, + 'store_id' => $this->defaultStoreId, + ] + ); + $this->assertRewrite( + $newSuffix, + [ + 'entity_type' => ProductUrlRewriteGenerator::ENTITY_TYPE, + 'entity_id' => $productId, + 'store_id' => $storeId, + ] + ); + } + + /** + * @magentoDbIsolation disabled + * + * @magentoDataFixture Magento/Catalog/_files/product_two_websites.php + * + * @return void + */ + public function testSaveInWebsiteScope(): void + { + $productId = (int)$this->productRepository->get('simple-on-two-websites')->getId(); + $newSuffix = 'some_test_value_for_website'; + $website = $this->storeManager->getWebsite('test'); + $this->model->addData([ + 'path' => ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX, + 'value' => $newSuffix, + 'scope' => ScopeInterface::SCOPE_WEBSITES, + 'scope_id' => $website->getId(), + ]); + $this->model->afterSave(); + $this->assertRewrite( + $this->scopeConfig->getValue(ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX), + [ + 'entity_type' => ProductUrlRewriteGenerator::ENTITY_TYPE, + 'entity_id' => $productId, + 'store_id' => $this->defaultStoreId, + ] + ); + $this->assertRewrite( + $newSuffix, + [ + 'entity_type' => ProductUrlRewriteGenerator::ENTITY_TYPE, + 'entity_id' => $productId, + 'store_id' => $website->getStoreIds(), + ] + ); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @magentoConfigFixture default_store catalog/seo/product_url_suffix .html_default + * + * @return void + */ + public function testSaveDefaultScopeWithOverrideStoreScope(): void + { + $productId = (int)$this->productRepository->get('simple2')->getId(); + $newSuffix = 'some_test_value'; + $this->model->addData([ + 'path' => ProductUrlPathGenerator::XML_PATH_PRODUCT_URL_SUFFIX, + 'value' => $newSuffix, + ]); + $this->model->afterSave(); + $this->assertRewrite( + '.html_default', + [ + 'entity_type' => ProductUrlRewriteGenerator::ENTITY_TYPE, + 'entity_id' => $productId, + 'store_id' => $this->defaultStoreId, + ] + ); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/category.php + * + * @return void + */ + public function testSaveCategorySuffix(): void + { + $this->model->addData(['path' => CategoryUrlPathGenerator::XML_PATH_CATEGORY_URL_SUFFIX, 'value' => null]); + $this->model->afterSave(); + $this->assertRewrite('.html', ['entity_type' => CategoryUrlRewriteGenerator::ENTITY_TYPE]); + $this->checkIsCacheInvalidated(); + } + + /** + * @return void + */ + public function testDeleteCategorySuffix(): void + { + $this->model->addData( + ['path' => CategoryUrlPathGenerator::XML_PATH_CATEGORY_URL_SUFFIX, 'value' => 'test_value'] + ); + $this->model->afterDeleteCommit(); + $this->checkIsCacheInvalidated(); + } + + /** + * Check that provided cache types are invalidated + * + * @param array $cacheTypes + * @return void + */ + private function checkIsCacheInvalidated( + array $cacheTypes = [Block::TYPE_IDENTIFIER, Collection::TYPE_IDENTIFIER] + ): void { + $types = $this->typeList->getTypes(); + + foreach ($cacheTypes as $type) { + $this->assertNotNull($types[$type]); + $this->assertEquals(0, $types[$type]->getStatus()); + } + } + + /** + * Assert url rewrite rewrite + * + * @param string $expectedSuffix + * @param array $data + * @return void + */ + private function assertRewrite(string $expectedSuffix, array $data) + { + $rewrite = $this->urlFinder->findOneByData($data); + $this->assertNotNull($rewrite); + $this->assertTrue( + substr($rewrite->getRequestPath(), -strlen($expectedSuffix)) === $expectedSuffix, + 'The url rewrite suffix does not match expected value' + ); + } +} From d2dd4ae4289ad572347b7397e9d2c11780d4aae0 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov <sidolov@adobe.com> Date: Wed, 23 Dec 2020 13:31:42 -0600 Subject: [PATCH 318/346] Revert removed step from the test --- .../Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml index 16b20abc0a583..739d5f0d40f61 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/CreditMemoTotalAfterShippingDiscountTest.xml @@ -62,6 +62,7 @@ <!-- Place an order from Storefront as a Guest --> <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> + <comment userInput="Adding the comment to replace action for preserving Backward Compatibility" stepKey="hoverOverProduct"/> <actionGroup ref="StorefrontHoverProductOnCategoryPageActionGroup" stepKey="hoverProduct"/> <actionGroup ref="StorefrontClickAddToCartButtonActionGroup" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductToAdd"/> From ae96ab2081185de784b282408afa7d84a28c9635 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 24 Dec 2020 13:10:32 +0200 Subject: [PATCH 319/346] MC-40078: Create automated test for: "Create attribute without attribute code" --- .../Product/Attribute/RepositoryTest.php | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php new file mode 100644 index 0000000000000..94a5b52b03c5f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php @@ -0,0 +1,145 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Product\Attribute; + +use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory; +use Magento\Catalog\Setup\CategorySetup; +use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; +use Magento\Framework\Exception\InputException; +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Checks product attribute save behaviour. + * + * @see \Magento\Catalog\Model\Product\Attribute\Repository + * + * @magentoDbIsolation enabled + */ +class RepositoryTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Repository */ + private $repository; + + /** @var ProductAttributeInterfaceFactory */ + private $attributeFactory; + + /** @var ProductAttributeInterface */ + private $createdAttribute; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->repository = $this->objectManager->get(Repository::class); + $this->attributeFactory = $this->objectManager->get(ProductAttributeInterfaceFactory::class); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + if ($this->createdAttribute instanceof ProductAttributeInterface) { + $this->repository->delete($this->createdAttribute); + } + + parent::tearDown(); + } + + /** + * @return void + */ + public function testSaveWithoutAttributeCode(): void + { + $this->createdAttribute = $this->saveAttributeWithData( + $this->hydrateData(['frontend_label' => 'Boolean Attribute']) + ); + $this->assertEquals('boolean_attribute', $this->createdAttribute->getAttributeCode()); + } + + /** + * @return void + */ + public function testSaveWithoutAttributeAndInvalidLabelCode(): void + { + $this->createdAttribute = $this->saveAttributeWithData($this->hydrateData(['frontend_label' => '/$&!/'])); + $this->assertStringStartsWith('attr_', $this->createdAttribute->getAttributeCode()); + } + + /** + * @dataProvider errorProvider + * + * @param string $fieldName + * @param string $fieldValue + * @return void + */ + public function testSaveWithInvalidCode(string $fieldName, string $fieldValue): void + { + $this->expectExceptionObject(InputException::invalidFieldValue($fieldName, $fieldValue)); + $this->createdAttribute = $this->saveAttributeWithData($this->hydrateData([$fieldName => $fieldValue])); + } + + /** + * @return array + */ + public function errorProvider():array + { + return [ + 'with_invalid_attribute_code' => [ + 'field_name' => 'attribute_code', + 'field_value' => '****', + ], + 'with_invalid_frontend_input' => [ + 'field_name' => 'frontend_input', + 'field_value' => 'invalid_input', + ], + ]; + } + + /** + * Save product attribute with data + * + * @param array $data + * @return ProductAttributeInterface + */ + private function saveAttributeWithData(array $data): ProductAttributeInterface + { + $attribute = $this->attributeFactory->create(); + $attribute->addData($data); + + return $this->repository->save($attribute); + } + + /** + * Hydrate data + * + * @param array $data + * @return array + */ + private function hydrateData(array $data): array + { + $defaultData = [ + 'entity_type_id' => CategorySetup::CATALOG_PRODUCT_ENTITY_TYPE_ID, + 'is_global' => ScopedAttributeInterface::SCOPE_GLOBAL, + 'frontend_input' => 'boolean', + 'frontend_label' => 'default label', + ]; + + return array_merge($defaultData, $data); + } +} From 06ca9b27abc155a844511d1a02fba8af13ac6dc2 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 24 Dec 2020 13:14:29 +0200 Subject: [PATCH 320/346] MC-39600: Create automated test for: "Change category/product url rewrite suffix in configurations" --- .../System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php index 6553dffb04df6..9979e8cd6ea68 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/System/Config/Backend/Catalog/Url/Rewrite/SuffixTest.php @@ -275,7 +275,7 @@ private function checkIsCacheInvalidated( * @param array $data * @return void */ - private function assertRewrite(string $expectedSuffix, array $data) + private function assertRewrite(string $expectedSuffix, array $data): void { $rewrite = $this->urlFinder->findOneByData($data); $this->assertNotNull($rewrite); From 772d1785ca60fd9a3c2c36f9779b14a01e3bc300 Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Thu, 24 Dec 2020 16:49:14 +0200 Subject: [PATCH 321/346] MC-36683: [Cloud]Generating companies... Could not save company --- setup/performance-toolkit/config/di.xml | 2 + .../Mail/Template/TransportBuilderMock.php | 28 ++++++++++++ .../Framework/Mail/TransportInterfaceMock.php | 45 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 setup/src/Magento/Setup/Framework/Mail/Template/TransportBuilderMock.php create mode 100644 setup/src/Magento/Setup/Framework/Mail/TransportInterfaceMock.php diff --git a/setup/performance-toolkit/config/di.xml b/setup/performance-toolkit/config/di.xml index 0b1175b0cd94c..a293edcb216af 100644 --- a/setup/performance-toolkit/config/di.xml +++ b/setup/performance-toolkit/config/di.xml @@ -6,4 +6,6 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <preference for="Magento\Framework\Mail\TransportInterface" type="Magento\Setup\Framework\Mail\TransportInterfaceMock"/> + <preference for="Magento\Framework\Mail\Template\TransportBuilder" type="Magento\Setup\Framework\Mail\Template\TransportBuilderMock"/> </config> diff --git a/setup/src/Magento/Setup/Framework/Mail/Template/TransportBuilderMock.php b/setup/src/Magento/Setup/Framework/Mail/Template/TransportBuilderMock.php new file mode 100644 index 0000000000000..2791487c37ba5 --- /dev/null +++ b/setup/src/Magento/Setup/Framework/Mail/Template/TransportBuilderMock.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Setup\Framework\Mail\Template; + +use Magento\Framework\Mail\Template\TransportBuilder; +use Magento\Setup\Framework\Mail\TransportInterfaceMock; + +/** + * Mock for mail template transport builder. + */ +class TransportBuilderMock extends TransportBuilder +{ + /** + * @inheritDoc + */ + public function getTransport() + { + $this->prepareMessage(); + $this->reset(); + + return new TransportInterfaceMock($this->message); + } +} diff --git a/setup/src/Magento/Setup/Framework/Mail/TransportInterfaceMock.php b/setup/src/Magento/Setup/Framework/Mail/TransportInterfaceMock.php new file mode 100644 index 0000000000000..64abddc053504 --- /dev/null +++ b/setup/src/Magento/Setup/Framework/Mail/TransportInterfaceMock.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Setup\Framework\Mail; + +use Magento\Framework\Mail\EmailMessageInterface; +use Magento\Framework\Mail\TransportInterface; + +/** + * Mock for mail transport. + */ +class TransportInterfaceMock implements TransportInterface +{ + /** + * @var EmailMessageInterface|null + */ + private $message; + + /** + * @param EmailMessageInterface|null $message + */ + public function __construct($message = null) + { + $this->message = $message; + } + + /** + * @inheritDoc + */ + public function sendMessage() + { + } + + /** + * @inheritDoc + */ + public function getMessage() + { + return $this->message; + } +} From fe4b27b89a4e4527a34d4fceb7d690ca1b51c3e6 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Thu, 24 Dec 2020 17:04:17 +0200 Subject: [PATCH 322/346] MC-40078: Create automated test for: "Create attribute without attribute code" --- .../Catalog/Model/Product/Attribute/RepositoryTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php index 94a5b52b03c5f..7430ebf72f8fb 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/RepositoryTest.php @@ -9,6 +9,7 @@ use Magento\Catalog\Api\Data\ProductAttributeInterface; use Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory; +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; use Magento\Catalog\Setup\CategorySetup; use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; use Magento\Framework\Exception\InputException; @@ -28,7 +29,7 @@ class RepositoryTest extends TestCase /** @var ObjectManagerInterface */ private $objectManager; - /** @var Repository */ + /** @var ProductAttributeRepositoryInterface */ private $repository; /** @var ProductAttributeInterfaceFactory */ @@ -45,7 +46,7 @@ protected function setUp(): void parent::setUp(); $this->objectManager = Bootstrap::getObjectManager(); - $this->repository = $this->objectManager->get(Repository::class); + $this->repository = $this->objectManager->get(ProductAttributeRepositoryInterface::class); $this->attributeFactory = $this->objectManager->get(ProductAttributeInterfaceFactory::class); } @@ -97,7 +98,7 @@ public function testSaveWithInvalidCode(string $fieldName, string $fieldValue): /** * @return array */ - public function errorProvider():array + public function errorProvider(): array { return [ 'with_invalid_attribute_code' => [ From 2c80277103eab5b9c497d6c6ef32e6103ef70b32 Mon Sep 17 00:00:00 2001 From: Roman Zhupanyn <roma.dj.elf@gmail.com> Date: Thu, 24 Dec 2020 18:19:13 +0200 Subject: [PATCH 323/346] MC-39711: Create automated test for: "Filter products in admin grid" --- .../AddQuantityFilterToCollectionTest.php | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollectionTest.php diff --git a/dev/tests/integration/testsuite/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollectionTest.php b/dev/tests/integration/testsuite/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollectionTest.php new file mode 100644 index 0000000000000..f0d87f06514f1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogInventory/Ui/DataProvider/Product/AddQuantityFilterToCollectionTest.php @@ -0,0 +1,133 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogInventory\Ui\DataProvider\Product; + +use Magento\Framework\App\RequestInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Framework\View\Element\UiComponentFactory; +use Magento\Framework\View\Element\UiComponentInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Checks that the product quantity filter is working correctly + * + * @magentoAppArea adminhtml + */ +class AddQuantityFilterToCollectionTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var UiComponentFactory */ + private $componentFactory; + + /** @var RequestInterface */ + private $request; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->request = $this->objectManager->get(RequestInterface::class); + $this->componentFactory = $this->objectManager->get(UiComponentFactory::class); + } + + /** + * @dataProvider quantityFilterProvider + * @magentoDataFixture Magento/Catalog/_files/multiple_products.php + * @param array $filter + * @param array $expectedProducts + * @return void + */ + public function testQuantityFilter(array $filter, array $expectedProducts): void + { + $this->request->setParams([ContextInterface::FILTER_VAR => $filter]); + $dataProviderData = $this->getComponentProvidedData('product_listing'); + $actualProducts = array_column($dataProviderData['items'], 'sku'); + $this->assertEquals($expectedProducts, $actualProducts, 'Expected products do not match actual products!'); + } + + /** + * Data provider for testQuantityFilter + * + * @return array + */ + public function quantityFilterProvider(): array + { + return [ + 'from' => [ + 'filter' => [ + 'qty' => [ + 'from' => 100, + ], + ], + 'expected_products' => [ + 'simple1', + 'simple3', + ], + ], + 'to' => [ + 'filter' => [ + 'qty' => [ + 'to' => 100, + ], + ], + 'expected_products' => [ + 'simple1', + 'simple2', + ], + ], + 'both' => [ + 'filter' => [ + 'qty' => [ + 'from' => 60, + 'to' => 130, + ], + ], + 'expected_products' => [ + 'simple1', + ], + ], + ]; + } + + /** + * Call prepare method in the child components + * + * @param UiComponentInterface $component + * @return void + */ + private function prepareChildComponents(UiComponentInterface $component): void + { + foreach ($component->getChildComponents() as $child) { + $this->prepareChildComponents($child); + } + + $component->prepare(); + } + + /** + * Get component provided data + * + * @param string $namespace + * @return array + */ + private function getComponentProvidedData(string $namespace): array + { + $component = $this->componentFactory->create($namespace); + $this->prepareChildComponents($component); + + return $component->getContext()->getDataProvider()->getData(); + } +} From f543cedd3c02ee717e23c22b833e2717566217a6 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 28 Dec 2020 10:55:29 +0200 Subject: [PATCH 324/346] MC-39575: Create automated test for "Apply visual swatch attribute filter on layered navigation" --- .../Configurable/Listing/ConfigurableTest.php | 115 ++++++++++++++++++ .../configurable_product_with_images.php | 41 +++++++ ...figurable_product_with_images_rollback.php | 15 +++ 3 files changed, 171 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php create mode 100644 dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php new file mode 100644 index 0000000000000..f2d254af85c94 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php @@ -0,0 +1,115 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Swatches\Block\Product\Renderer\Configurable\Listing; + +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\Module\Manager; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\View\LayoutInterface; +use Magento\Swatches\Block\Product\Renderer\Listing\Configurable; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Tests for configurable products options block with swatch attribute. + * + * @magentoDbIsolation enabled + * @magentoAppArea frontend + */ +class ConfigurableTest extends TestCase +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var SerializerInterface + */ + private $serializer; + + /** + * @var Configurable + */ + private $block; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @var ProductAttributeRepositoryInterface + */ + private $productAttributeRepository; + + /** + * @var RequestInterface + */ + private $request; + + /** + * @inheritdoc + */ + public static function setUpBeforeClass(): void + { + $objectManager = Bootstrap::getObjectManager(); + /** @var Manager $moduleManager */ + $moduleManager = $objectManager->get(Manager::class); + if (!$moduleManager->isEnabled('Magento_Catalog')) { + self::markTestSkipped('Magento_Catalog module disabled.'); + } + } + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->serializer = $this->objectManager->get(SerializerInterface::class); + $this->productAttributeRepository = $this->objectManager->get(ProductAttributeRepositoryInterface::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(Configurable::class); + $this->request = $this->objectManager->get(RequestInterface::class); + $this->request->clearParams(); + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + $this->request->clearParams(); + + parent::tearDown(); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/configurable_product_with_images.php + * @return void + */ + public function testPreSelectedGalleryConfig(): void + { + $product = $this->productRepository->get('configurable'); + $this->block->setProduct($product); + $configurableAttribute = $this->productAttributeRepository->get('visual_swatch_attribute'); + $this->request->setQueryValue('visual_swatch_attribute', $configurableAttribute->getOptions()[1]->getValue()); + $jsonConfig = $this->serializer->unserialize($this->block->getJsonConfig()); + $this->assertArrayHasKey('preSelectedGallery', $jsonConfig); + $this->assertStringEndsWith('/m/a/magento_image.jpg', $jsonConfig['preSelectedGallery']['large']); + $this->assertStringEndsWith('/m/a/magento_image.jpg', $jsonConfig['preSelectedGallery']['medium']); + $this->assertStringEndsWith('/m/a/magento_image.jpg', $jsonConfig['preSelectedGallery']['small']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php new file mode 100644 index 0000000000000..096674c5e9620 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\Data\ProductExtensionInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\ProductFactory; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture( + 'Magento/Catalog/_files/product_image.php' +); +Resolver::getInstance()->requireDataFixture( + 'Magento/Swatches/_files/configurable_product_visual_swatch_attribute.php' +); + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$images = ['magento_image.jpg', 'magento_small_image.jpg', 'magento_thumbnail.jpg']; +foreach (range(1, 3) as $index) { + $product = $productRepository->get('simple_option_' . $index); + $product->setImage('/m/a/' . $images[$index - 1]) + ->setSmallImage('/m/a/' . $images[$index - 1]) + ->setThumbnail('/m/a/' . $images[$index - 1]) + ->setData('media_gallery', ['images' => [ + [ + 'file' => '/m/a/' . $images[$index - 1], + 'position' => 1, + 'label' => 'Image Alt Text', + 'disabled' => 0, + 'media_type' => 'image', + ], + ]]) + ->setCanSaveCustomOptions(true) + ->save(); +} diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images_rollback.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images_rollback.php new file mode 100644 index 0000000000000..c201b258c5341 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images_rollback.php @@ -0,0 +1,15 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture( + 'Magento/Swatches/_files/configurable_product_visual_swatch_attribute_rollback.php' +); +Resolver::getInstance()->requireDataFixture( + 'Magento/Catalog/_files/product_image_rollback.php' +); From a68e58e59a5bf0bd30b0e5b254a867e6d4d9f3bd Mon Sep 17 00:00:00 2001 From: mastiuhin-olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Mon, 28 Dec 2020 11:45:41 +0200 Subject: [PATCH 325/346] MC-39878: Invoice for an order that contains only one configurable product is not generated correctly --- .../Magento/Sales/Model/Order/Invoice.php | 5 ++ .../Magento/Sales/Model/Order/InvoiceTest.php | 69 +++++++++++++++++-- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Sales/Model/Order/Invoice.php b/app/code/Magento/Sales/Model/Order/Invoice.php index 14dd0b14ac1f3..50bbb3083a9ea 100644 --- a/app/code/Magento/Sales/Model/Order/Invoice.php +++ b/app/code/Magento/Sales/Model/Order/Invoice.php @@ -679,6 +679,11 @@ public function register() public function isLast() { foreach ($this->getAllItems() as $item) { + $orderItem = $item->getOrderItem(); + if ($orderItem->isDummy()) { + continue; + } + if (!$item->isLast()) { return false; } diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/InvoiceTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/InvoiceTest.php index 8abec6ac6d734..64d5cdb037343 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/InvoiceTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/InvoiceTest.php @@ -3,20 +3,57 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Sales\Model\Order; -class InvoiceTest extends \PHPUnit\Framework\TestCase +use PHPUnit\Framework\TestCase; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Sales\Model\ResourceModel\Order\Collection as OrderCollection; +use Magento\Sales\Api\InvoiceManagementInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; + +/** + * Invoice model test. + */ +class InvoiceTest extends TestCase { /** - * @var \Magento\Sales\Model\ResourceModel\Order\Collection + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var OrderCollection + */ + private $collection; + + /** + * @var InvoiceManagementInterface + */ + private $invoiceManagement; + + /** + * @var OrderRepositoryInterface + */ + private $orderRepository; + + /** + * @var SearchCriteriaBuilder */ - private $_collection; + private $searchCriteriaBuilder; + /** + * @inheritDoc + */ protected function setUp(): void { - $this->_collection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Sales\Model\ResourceModel\Order\Collection::class - ); + $this->objectManager = Bootstrap::getObjectManager(); + $this->collection = $this->objectManager->create(OrderCollection::class); + $this->invoiceManagement = $this->objectManager->get(InvoiceManagementInterface::class); + $this->orderRepository = $this->objectManager->get(OrderRepositoryInterface::class); + $this->searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); } /** @@ -27,9 +64,27 @@ public function testOrderTotalItemCount() $expectedResult = [['total_item_count' => 1]]; $actualResult = []; /** @var \Magento\Sales\Model\Order $order */ - foreach ($this->_collection->getItems() as $order) { + foreach ($this->collection->getItems() as $order) { $actualResult[] = ['total_item_count' => $order->getData('total_item_count')]; } $this->assertEquals($expectedResult, $actualResult); } + + /** + * Test order with exactly one configurable. + * + * @return void + * @magentoDataFixture Magento/Sales/_files/order_configurable_product.php + */ + public function testLastInvoiceWithConfigurable(): void + { + $searchCriteria = $this->searchCriteriaBuilder->addFilter('increment_id', '100000001') + ->create(); + $orders = $this->orderRepository->getList($searchCriteria); + $orders = $orders->getItems(); + $order = array_shift($orders); + $invoice = $this->invoiceManagement->prepareInvoice($order); + + self::assertEquals($invoice->isLast(), true); + } } From 6293b241f6469dcac784808905fae564142ce2d8 Mon Sep 17 00:00:00 2001 From: Serhii Balko <serhii.balko@transogtgroup.com> Date: Mon, 28 Dec 2020 11:59:10 +0200 Subject: [PATCH 326/346] MC-39864: [Magento Cloud] - Tax Miscalculation --- .../Model/Order/Creditmemo/Total/TaxTest.php | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php index 7c9d249124a9a..f6d7c6fdba60a 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php @@ -192,7 +192,7 @@ public function collectDataProvider() 'base_shipping_amount' => 30, 'tax_amount' => 0.82, 'base_tax_amount' => 0.82, - 'invoice' => new MagentoObject( + 'invoice' => $this->createInvoiceMock( [ 'tax_amount' => 24.33, 'base_tax_amount' => 24.33, @@ -283,7 +283,7 @@ public function collectDataProvider() 'base_shipping_amount' => 30, 'tax_amount' => 0.82 * $currencyRatio, 'base_tax_amount' => 0.82, - 'invoice' => new MagentoObject( + 'invoice' => $this->createInvoiceMock( [ 'tax_amount' => 24.33 * $currencyRatio, 'base_tax_amount' => 24.33, @@ -360,7 +360,7 @@ public function collectDataProvider() 'base_shipping_amount' => 30, 'tax_amount' => 1.65, 'base_tax_amount' => 1.65, - 'invoice' => new MagentoObject( + 'invoice' => $this->createInvoiceMock( [ 'tax_amount' => 11.14, 'base_tax_amount' => 11.14, @@ -438,7 +438,7 @@ public function collectDataProvider() 'base_shipping_amount' => 0, 'tax_amount' => 0.82, 'base_tax_amount' => 0.82, - 'invoice' => new MagentoObject( + 'invoice' => $this->createInvoiceMock( [ 'tax_amount' => 16.09, 'base_tax_amount' => 16.09, @@ -587,7 +587,7 @@ public function collectDataProvider() 'base_grand_total' => 60.82, 'tax_amount' => 0.82, 'base_tax_amount' => 0.82, - 'invoice' => new MagentoObject( + 'invoice' => $this->createInvoiceMock( [ 'tax_amount' => 16.09, 'base_tax_amount' => 16.09, @@ -779,4 +779,40 @@ protected function getCreditmemoItem($creditmemoItemData) $creditmemoItem->setData('qty', $creditmemoItemData['qty']); return $creditmemoItem; } + + /** + * Create invoice mock object + * + * @param array $data + * @return MockObject|Invoice + */ + private function createInvoiceMock(array $data): MockObject + { + /** @var MockObject|Invoice $invoice */ + $invoice = $this->getMockBuilder(Invoice::class) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->disableArgumentCloning() + ->disallowMockingUnknownTypes() + ->addMethods(['getBaseShippingDiscountTaxCompensationAmount']) + ->onlyMethods([ + 'getTaxAmount', + 'getBaseTaxAmount', + 'getShippingTaxAmount', + 'getBaseShippingTaxAmount', + 'getShippingDiscountTaxCompensationAmount' + ]) + ->getMock(); + + $invoice->method('getTaxAmount')->willReturn($data['tax_amount'] ?? 0); + $invoice->method('getBaseTaxAmount')->willReturn($data['base_tax_amount'] ?? 0); + $invoice->method('getShippingTaxAmount')->willReturn($data['shipping_tax_amount'] ?? 0); + $invoice->method('getBaseShippingTaxAmount')->willReturn($data['base_shipping_tax_amount'] ?? 0); + $invoice->method('getShippingDiscountTaxCompensationAmount') + ->willReturn($data['shipping_discount_tax_compensation_amount'] ?? 0); + $invoice->method('getBaseShippingDiscountTaxCompensationAmount') + ->willReturn($data['base_shipping_discount_tax_compensation_amount'] ?? 0); + + return $invoice; + } } From 7491d77c7b8de8a29c5d118796a67f3cb0dcfd8e Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 28 Dec 2020 13:48:51 +0200 Subject: [PATCH 327/346] MC-39575: Create automated test for "Apply visual swatch attribute filter on layered navigation" --- .../Configurable/Listing/ConfigurableTest.php | 11 ----------- .../_files/configurable_product_with_images.php | 14 +++++++------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php index f2d254af85c94..58475ea879094 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/Configurable/Listing/ConfigurableTest.php @@ -83,17 +83,6 @@ protected function setUp(): void $this->productRepository->cleanCache(); $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(Configurable::class); $this->request = $this->objectManager->get(RequestInterface::class); - $this->request->clearParams(); - } - - /** - * @inheritdoc - */ - protected function tearDown(): void - { - $this->request->clearParams(); - - parent::tearDown(); } /** diff --git a/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php index 096674c5e9620..f2bcbc27dc01a 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/_files/configurable_product_with_images.php @@ -7,7 +7,6 @@ use Magento\Catalog\Api\Data\ProductExtensionInterfaceFactory; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Catalog\Model\ProductFactory; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Workaround\Override\Fixture\Resolver; @@ -21,15 +20,16 @@ $objectManager = Bootstrap::getObjectManager(); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $objectManager->get(ProductRepositoryInterface::class); +$configurableProduct = $productRepository->get('configurable'); +$children = $configurableProduct->getTypeInstance()->getUsedProducts($configurableProduct); $images = ['magento_image.jpg', 'magento_small_image.jpg', 'magento_thumbnail.jpg']; -foreach (range(1, 3) as $index) { - $product = $productRepository->get('simple_option_' . $index); - $product->setImage('/m/a/' . $images[$index - 1]) - ->setSmallImage('/m/a/' . $images[$index - 1]) - ->setThumbnail('/m/a/' . $images[$index - 1]) +foreach ($children as $index => $product) { + $product->setImage('/m/a/' . $images[$index]) + ->setSmallImage('/m/a/' . $images[$index]) + ->setThumbnail('/m/a/' . $images[$index]) ->setData('media_gallery', ['images' => [ [ - 'file' => '/m/a/' . $images[$index - 1], + 'file' => '/m/a/' . $images[$index], 'position' => 1, 'label' => 'Image Alt Text', 'disabled' => 0, From 9e4001b88bd20b2503dc6845a6eae715aa440f4e Mon Sep 17 00:00:00 2001 From: engcom-Kilo <mikola.malevanec@transoftgroup.com> Date: Mon, 28 Dec 2020 16:54:28 +0200 Subject: [PATCH 328/346] MC-39189: Exception on Admin Customers page when website is deleted. --- .../Component/Listing/Column/Confirmation.php | 34 +++-- .../Listing/Column/ConfirmationTest.php | 127 ++++++++++++++++++ 2 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Customer/Ui/Component/Listing/Column/ConfirmationTest.php diff --git a/app/code/Magento/Customer/Ui/Component/Listing/Column/Confirmation.php b/app/code/Magento/Customer/Ui/Component/Listing/Column/Confirmation.php index 26cac677ccd10..6215909a1fbee 100644 --- a/app/code/Magento/Customer/Ui/Component/Listing/Column/Confirmation.php +++ b/app/code/Magento/Customer/Ui/Component/Listing/Column/Confirmation.php @@ -6,6 +6,7 @@ namespace Magento\Customer\Ui\Component\Listing\Column; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\View\Element\UiComponent\ContextInterface; use Magento\Framework\View\Element\UiComponentFactory; use Magento\Ui\Component\Listing\Columns\Column; @@ -28,7 +29,7 @@ class Confirmation extends Column * @param ScopeConfigInterface $scopeConfig @deprecated * @param array $components * @param array $data - * @param AccountConfirmation $accountConfirmation + * @param AccountConfirmation|null $accountConfirmation * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( @@ -65,13 +66,7 @@ public function prepareDataSource(array $dataSource) */ private function getFieldLabel(array $item) { - $isConfirmationRequired = $this->accountConfirmation->isConfirmationRequired( - $item['website_id'][0] ?? null, - $item[$item['id_field_name']], - $item['email'] - ); - - if ($isConfirmationRequired) { + if ($this->getIsConfirmationRequired($item)) { if ($item[$this->getData('name')] === null) { return __('Confirmed'); } @@ -79,4 +74,27 @@ private function getFieldLabel(array $item) } return __('Confirmation Not Required'); } + + /** + * Retrieve is confirmation required flag for customer considering requested website may not exist. + * + * @param array $customer + * @return bool + */ + private function getIsConfirmationRequired(array $customer): bool + { + try { + return $this->accountConfirmation->isConfirmationRequired( + $customer['website_id'][0] ?? null, + $customer[$customer['id_field_name']], + $customer['email'] + ); + } catch (NoSuchEntityException $e) { + return $this->accountConfirmation->isConfirmationRequired( + null, + $customer[$customer['id_field_name']], + $customer['email'] + ); + } + } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Ui/Component/Listing/Column/ConfirmationTest.php b/dev/tests/integration/testsuite/Magento/Customer/Ui/Component/Listing/Column/ConfirmationTest.php new file mode 100644 index 0000000000000..24fe443c8c796 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Customer/Ui/Component/Listing/Column/ConfirmationTest.php @@ -0,0 +1,127 @@ +<?php + +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Customer\Ui\Component\Listing\Column; + +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Tests for \Magento\Customer\Ui\Component\Listing\Column\Confirmation. + */ +class ConfirmationTest extends TestCase +{ + /** + * Test subject. + * + * @var Confirmation + */ + private $confirmation; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + $this->confirmation = Bootstrap::getObjectManager()->create( + Confirmation::class, + [ + 'components' => [], + 'data' => ['name' => 'confirmation'], + ] + ); + } + + /** + * Verify Confirmation::prepareDataSource() won't throw exception in case requested website doesn't exist. + * + * @param array $customerDataSource + * @param array $expectedResult + * @magentoConfigFixture base_website customer/create_account/confirm 1 + * @dataProvider customersDataProvider + * + * @return void + */ + public function testPrepareDataSource(array $customerDataSource, array $expectedResult): void + { + $result = $this->confirmation->prepareDataSource($customerDataSource); + + self::assertEquals($expectedResult, $result); + } + + /** + * CustomerDataSource data provider. + * + * @return array + */ + public function customersDataProvider(): array + { + return [ + [ + 'customerDataSource' => [ + 'data' => [ + 'items' => [ + [ + 'id_field_name' => 'entity_id', + 'entity_id' => '1', + 'name' => 'John Doe', + 'email' => 'john.doe@example.com', + 'group_id' => ['1'], + 'created_at' => '2020-12-28 07:05:50', + 'website_id' => ['1'], + 'confirmation' => false, + 'created_in' => 'Default Store View', + ], + [ + 'id_field_name' => 'entity_id', + 'entity_id' => '2', + 'name' => 'Jane Doe', + 'email' => 'jane.doe@example.com', + 'group_id' => ['1'], + 'created_at' => '2020-12-28 07:06:17', + 'website_id' => ['999999999'], + 'confirmation' => null, + 'created_in' => 'CustomStoreViewWhichDoesNotExistAnymore', + ], + ], + 'totalRecords' => 2, + ], + ], + 'expectedResult' => [ + 'data' => [ + 'items' => [ + [ + 'id_field_name' => 'entity_id', + 'entity_id' => '1', + 'name' => 'John Doe', + 'email' => 'john.doe@example.com', + 'group_id' => ['1'], + 'created_at' => '2020-12-28 07:05:50', + 'website_id' => ['1'], + 'confirmation' => __('Confirmation Required'), + 'created_in' => 'Default Store View', + ], + [ + 'id_field_name' => 'entity_id', + 'entity_id' => '2', + 'name' => 'Jane Doe', + 'email' => 'jane.doe@example.com', + 'group_id' => ['1'], + 'created_at' => '2020-12-28 07:06:17', + 'website_id' => ['999999999'], + 'confirmation' => __('Confirmed'), + 'created_in' => 'CustomStoreViewWhichDoesNotExistAnymore', + ], + ], + 'totalRecords' => 2, + ], + ], + ], + ]; + } +} From 640adcdfe746f3d9acf5c6bd7afa24dd2b42a1bb Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 29 Dec 2020 11:15:27 +0200 Subject: [PATCH 329/346] MC-39598: Create automated test for: "Assign/Unassign product to websites via API" --- .../Api/ProductWebsiteLinkRepositoryTest.php | 113 ++++++++++++++++++ .../ProductWebsiteLinkRepositoryTest.php | 72 +++++++++++ 2 files changed, 185 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php new file mode 100644 index 0000000000000..13218450e5054 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php @@ -0,0 +1,113 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Api; + +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Webapi\Rest\Request; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Tests to check products to websites assigning. + * + * @see \Magento\Catalog\Model\ProductWebsiteLinkRepository + * + * @magentoAppIsolation enabled + */ +class ProductWebsiteLinkRepositoryTest extends WebapiAbstract +{ + const SERVICE_NAME = 'catalogProductWebsiteLinkRepositoryV1'; + const SERVICE_VERSION = 'V1'; + + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var WebsiteRepositoryInterface */ + private $websiteRepository; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testSaveWebsiteLinkWithoutWebsiteId(): void + { + $serviceInfo = $this->fillServiceInfo('/V1/products/:sku/websites', Request::HTTP_METHOD_POST, 'Save'); + $requestData = ['productWebsiteLink' => ['sku' => 'simple2']]; + $this->expectException(\Exception::class); + $this->expectErrorMessage((string)__('There are not websites for assign to product')); + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testSaveWebsiteLinkWithUnexistingWebsiteId(): void + { + $unexistingWebsiteId = 8932568989; + $serviceInfo = $this->fillServiceInfo('/V1/products/:sku/websites', Request::HTTP_METHOD_POST, 'Save'); + $requestData = ['productWebsiteLink' => ['sku' => 'simple2', 'websiteId' => $unexistingWebsiteId]]; + $this->expectException(\Exception::class); + $this->expectExceptionMessageMatches('/Could not assign product \\\"%1\\\" to websites \\\"%2\\\"/'); + $this->_webApiCall($serviceInfo, $requestData); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_two_websites.php + * + * @return void + */ + public function testDeleteWebsiteLink(): void + { + $productSku = 'unique-simple-azaza'; + $websiteId = (int)$this->websiteRepository->get('second_website')->getId(); + $resourcePath = sprintf('/V1/products/%s/websites/%u', $productSku, $websiteId); + $serviceInfo = $this->fillServiceInfo($resourcePath, Request::HTTP_METHOD_DELETE, 'Delete'); + $this->_webApiCall($serviceInfo); + $product = $this->productRepository->get($productSku, false, null, true); + $this->assertNotContains($websiteId, $product->getWebsiteIds()); + } + + /** + * Fill service information + * + * @param string $resourcePath + * @param string $httpMethod + * @param string $operation + * @return array + */ + private function fillServiceInfo(string $resourcePath, string $httpMethod, string $operation): array + { + return [ + 'rest' => ['resourcePath' => $resourcePath, 'httpMethod' => $httpMethod], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . $operation, + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php new file mode 100644 index 0000000000000..a4441c9480b25 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model; + +use Magento\Catalog\Api\Data\ProductWebsiteLinkInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Tests to check products to websites assigning. + * + * @see \Magento\Catalog\Model\ProductWebsiteLinkRepository + * + * @magentoAppIsolation enabled + */ +class ProductWebsiteLinkRepositoryTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var ProductWebsiteLinkRepositoryInterface */ + private $productWebsiteLinkRepository; + + /** @var ProductWebsiteLinkInterfaceFactory */ + private $productWebsiteLinkFactory; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** @var WebsiteRepositoryInterface */ + private $websiteRepository; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->productWebsiteLinkRepository = $this->objectManager->get(ProductWebsiteLinkRepositoryInterface::class); + $this->productWebsiteLinkFactory = $this->objectManager->get(ProductWebsiteLinkInterfaceFactory::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->productRepository->cleanCache(); + $this->websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/product_with_two_websites.php + * + * @return void + */ + public function testDelete(): void + { + $this->markTestSkipped('Blocked by MC-40250'); + $productWebsiteLink = $this->productWebsiteLinkFactory->create(); + $productWebsiteLink->setSku('unique-simple-azaza'); + $productWebsiteLink->setWebsiteId(1); + $this->productWebsiteLinkRepository->delete($productWebsiteLink); + $product = $this->productRepository->get('unique-simple-azaza', false, null, true); + $this->assertEquals([$this->websiteRepository->get('second_website')->getId()], $product->getWebsiteIds()); + } +} From 0073eb38787d4c52981bcb2981f335a73f6bf3b0 Mon Sep 17 00:00:00 2001 From: rostyslav-hymon <rostyslav.hymon@transoftgroup.com> Date: Tue, 29 Dec 2020 13:48:23 +0200 Subject: [PATCH 330/346] MC-39276: Can not change value for Ship Bundle Item attribute if it was moved to different group --- .../Product/Form/Modifier/BundlePanelTest.php | 166 ++++++++++++++++++ .../Product/Form/Modifier/BundlePanel.php | 17 +- 2 files changed, 176 insertions(+), 7 deletions(-) create mode 100644 app/code/Magento/Bundle/Test/Unit/Ui/DataProvider/Product/Form/Modifier/BundlePanelTest.php diff --git a/app/code/Magento/Bundle/Test/Unit/Ui/DataProvider/Product/Form/Modifier/BundlePanelTest.php b/app/code/Magento/Bundle/Test/Unit/Ui/DataProvider/Product/Form/Modifier/BundlePanelTest.php new file mode 100644 index 0000000000000..51563d319dfc8 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Unit/Ui/DataProvider/Product/Form/Modifier/BundlePanelTest.php @@ -0,0 +1,166 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Bundle\Test\Unit\Ui\DataProvider\Product\Form\Modifier; + +use Magento\Bundle\Model\Product\Attribute\Source\Shipment\Type as ShipmentType; +use Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePanel; +use Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\BundlePrice; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Locator\LocatorInterface; +use Magento\Framework\Stdlib\ArrayManager; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\UrlInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Test for bundle panel + */ +class BundlePanelTest extends TestCase +{ + /** + * @var UrlInterface|MockObject + */ + private $urlBuilder; + + /** + * @var ShipmentType|MockObject + */ + private $shipmentType; + + /** + * @var LocatorInterface|MockObject + */ + private $locatorMock; + + /** + * @var ProductInterface|MockObject + */ + private $productMock; + + /** + * @var ArrayManager|MockObject + */ + private $arrayManagerMock; + + /** + * @var BundlePanel + */ + private $bundlePanelModel; + + /** + * @return void + */ + protected function setUp(): void + { + $this->objectManager = new ObjectManager($this); + $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->arrayManagerMock->expects($this->any()) + ->method('get') + ->willReturn([]); + $this->urlBuilder = $this->getMockBuilder(UrlInterface::class) + ->getMockForAbstractClass(); + $this->shipmentType = $this->getMockBuilder(ShipmentType::class) + ->getMockForAbstractClass(); + $this->productMock = $this->getMockBuilder(ProductInterface::class) + ->addMethods(['getStoreId']) + ->getMockForAbstractClass(); + $this->productMock->method('getId') + ->willReturn(true); + $this->productMock->method('getStoreId') + ->willReturn(0); + $this->locatorMock = $this->getMockBuilder(LocatorInterface::class) + ->onlyMethods(['getProduct']) + ->getMockForAbstractClass(); + $this->locatorMock->method('getProduct') + ->willReturn($this->productMock); + + $this->bundlePanelModel = $this->objectManager->getObject( + BundlePanel::class, + [ + 'locator' => $this->locatorMock, + 'urlBuilder' => $this->urlBuilder, + 'shipmentType' => $this->shipmentType, + 'arrayManager' => $this->arrayManagerMock, + ] + ); + } + + /** + * Test for modify meta + * + * @param string $shipmentTypePath + * @param string $dataScope + * + * @return void + * @dataProvider getDataModifyMeta + */ + public function testModifyMeta(string $shipmentTypePath, string $dataScope): void + { + $sourceMeta = [ + 'bundle-items' => [ + 'children' => [ + BundlePrice::CODE_PRICE_TYPE => [] + ] + ] + ]; + $this->arrayManagerMock->method('findPath') + ->willReturnMap( + [ + [ + BundlePanel::CODE_SHIPMENT_TYPE, + [], + null, + 'children', + ArrayManager::DEFAULT_PATH_DELIMITER, + $shipmentTypePath + ], + ] + ); + $this->arrayManagerMock->method('merge') + ->willReturn([]); + $this->arrayManagerMock->method('remove') + ->willReturn([]); + $this->arrayManagerMock->method('set') + ->willReturn([]); + $this->arrayManagerMock->expects($this->at(12)) + ->method('merge') + ->with( + $shipmentTypePath . BundlePanel::META_CONFIG_PATH, + [], + [ + 'dataScope' => $dataScope, + 'validation' => [ + 'required-entry' => false + ] + ] + ); + $this->bundlePanelModel->modifyMeta($sourceMeta); + } + + /** + * Data provider for modify meta test + * + * @return string[][] + */ + public function getDataModifyMeta(): array + { + return [ + [ + 'bundle-items/children', + 'data.product.shipment_type' + ], + [ + 'someAttrGroup/children', + 'shipment_type' + ], + ]; + } +} diff --git a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php index 5ff9e674acad9..01b113def9243 100644 --- a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php +++ b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php @@ -252,16 +252,19 @@ public function modifyData(array $data) */ private function modifyShipmentType(array $meta) { + $actualPath = $this->arrayManager->findPath( + static::CODE_SHIPMENT_TYPE, + $meta, + null, + 'children' + ); + $meta = $this->arrayManager->merge( - $this->arrayManager->findPath( - static::CODE_SHIPMENT_TYPE, - $meta, - null, - 'children' - ) . static::META_CONFIG_PATH, + $actualPath . static::META_CONFIG_PATH, $meta, [ - 'dataScope' => 'data.product.shipment_type', + 'dataScope' => stripos($actualPath, self::CODE_BUNDLE_DATA) === 0 + ? 'data.product.shipment_type' : 'shipment_type', 'validation' => [ 'required-entry' => false ] From 04fd1acd367593c5080075d31602ca7dd68b70ca Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 29 Dec 2020 14:15:22 +0200 Subject: [PATCH 331/346] MC-39598: Create automated test for: "Assign/Unassign product to websites via API" --- .../Api/ProductWebsiteLinkRepositoryTest.php | 21 ++++--------------- .../ProductWebsiteLinkRepositoryTest.php | 17 ++++++++++++++- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php index 13218450e5054..fbca54acc9e0b 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php @@ -46,20 +46,6 @@ protected function setUp(): void $this->websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class); } - /** - * @magentoApiDataFixture Magento/Catalog/_files/second_product_simple.php - * - * @return void - */ - public function testSaveWebsiteLinkWithoutWebsiteId(): void - { - $serviceInfo = $this->fillServiceInfo('/V1/products/:sku/websites', Request::HTTP_METHOD_POST, 'Save'); - $requestData = ['productWebsiteLink' => ['sku' => 'simple2']]; - $this->expectException(\Exception::class); - $this->expectErrorMessage((string)__('There are not websites for assign to product')); - $this->_webApiCall($serviceInfo, $requestData); - } - /** * @magentoApiDataFixture Magento/Catalog/_files/second_product_simple.php * @@ -67,11 +53,12 @@ public function testSaveWebsiteLinkWithoutWebsiteId(): void */ public function testSaveWebsiteLinkWithUnexistingWebsiteId(): void { + $pattern = '/(Could\\snot\\sassign\\sproduct)+([\\s\\S]*)(to\\swebsites)+([\\s\\S]*)/'; $unexistingWebsiteId = 8932568989; $serviceInfo = $this->fillServiceInfo('/V1/products/:sku/websites', Request::HTTP_METHOD_POST, 'Save'); $requestData = ['productWebsiteLink' => ['sku' => 'simple2', 'websiteId' => $unexistingWebsiteId]]; $this->expectException(\Exception::class); - $this->expectExceptionMessageMatches('/Could not assign product \\\"%1\\\" to websites \\\"%2\\\"/'); + $this->expectExceptionMessageMatches($pattern); $this->_webApiCall($serviceInfo, $requestData); } @@ -85,8 +72,8 @@ public function testDeleteWebsiteLink(): void $productSku = 'unique-simple-azaza'; $websiteId = (int)$this->websiteRepository->get('second_website')->getId(); $resourcePath = sprintf('/V1/products/%s/websites/%u', $productSku, $websiteId); - $serviceInfo = $this->fillServiceInfo($resourcePath, Request::HTTP_METHOD_DELETE, 'Delete'); - $this->_webApiCall($serviceInfo); + $serviceInfo = $this->fillServiceInfo($resourcePath, Request::HTTP_METHOD_DELETE, 'DeleteById'); + $this->_webApiCall($serviceInfo, ['sku' => $productSku, 'websiteId' => $websiteId]); $product = $this->productRepository->get($productSku, false, null, true); $this->assertNotContains($websiteId, $product->getWebsiteIds()); } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php index a4441c9480b25..9ae327036971b 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductWebsiteLinkRepositoryTest.php @@ -10,6 +10,7 @@ use Magento\Catalog\Api\Data\ProductWebsiteLinkInterfaceFactory; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Api\ProductWebsiteLinkRepositoryInterface; +use Magento\Framework\Exception\InputException; use Magento\Framework\ObjectManagerInterface; use Magento\Store\Api\WebsiteRepositoryInterface; use Magento\TestFramework\Helper\Bootstrap; @@ -55,7 +56,21 @@ protected function setUp(): void } /** - * @magentoApiDataFixture Magento/Catalog/_files/product_with_two_websites.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * + * @return void + */ + public function testSaveWithoutWebsiteId(): void + { + $productWebsiteLink = $this->productWebsiteLinkFactory->create(); + $productWebsiteLink->setSku('unique-simple-azaza'); + $this->expectException(InputException::class); + $this->expectErrorMessage((string)__('There are not websites for assign to product')); + $this->productWebsiteLinkRepository->save($productWebsiteLink); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_with_two_websites.php * * @return void */ From 9b0799b75169c7df4e85a647187e15512f71befc Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 29 Dec 2020 19:07:46 +0200 Subject: [PATCH 332/346] MC-39598: Create automated test for: "Assign/Unassign product to websites via API" --- .../Api/ProductWebsiteLinkRepositoryTest.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php index fbca54acc9e0b..0bbed6387ae57 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductWebsiteLinkRepositoryTest.php @@ -7,6 +7,7 @@ namespace Magento\Catalog\Api; +use Magento\Catalog\Model\ProductWebsiteLink; use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Webapi\Rest\Request; use Magento\Store\Api\WebsiteRepositoryInterface; @@ -56,7 +57,12 @@ public function testSaveWebsiteLinkWithUnexistingWebsiteId(): void $pattern = '/(Could\\snot\\sassign\\sproduct)+([\\s\\S]*)(to\\swebsites)+([\\s\\S]*)/'; $unexistingWebsiteId = 8932568989; $serviceInfo = $this->fillServiceInfo('/V1/products/:sku/websites', Request::HTTP_METHOD_POST, 'Save'); - $requestData = ['productWebsiteLink' => ['sku' => 'simple2', 'websiteId' => $unexistingWebsiteId]]; + $requestData = [ + 'productWebsiteLink' => [ + ProductWebsiteLink::KEY_SKU => 'simple2', + ProductWebsiteLink::WEBSITE_ID => $unexistingWebsiteId, + ], + ]; $this->expectException(\Exception::class); $this->expectExceptionMessageMatches($pattern); $this->_webApiCall($serviceInfo, $requestData); @@ -73,7 +79,10 @@ public function testDeleteWebsiteLink(): void $websiteId = (int)$this->websiteRepository->get('second_website')->getId(); $resourcePath = sprintf('/V1/products/%s/websites/%u', $productSku, $websiteId); $serviceInfo = $this->fillServiceInfo($resourcePath, Request::HTTP_METHOD_DELETE, 'DeleteById'); - $this->_webApiCall($serviceInfo, ['sku' => $productSku, 'websiteId' => $websiteId]); + $this->_webApiCall( + $serviceInfo, + [ProductWebsiteLink::KEY_SKU => $productSku, ProductWebsiteLink::WEBSITE_ID => $websiteId] + ); $product = $this->productRepository->get($productSku, false, null, true); $this->assertNotContains($websiteId, $product->getWebsiteIds()); } From 2740e08869dfc8b0ea69bd20400c693e82c73a1b Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 30 Dec 2020 13:01:01 +0200 Subject: [PATCH 333/346] MC-40068: Create automated test for: "Try to delete root category by API call" --- .../Catalog/Api/CategoryRepositoryTest.php | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php index 5623edca62b9a..8e0aff81cc3b8 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php @@ -184,22 +184,49 @@ public function testDeleteNoSuchEntityException() /** * @dataProvider deleteSystemOrRootDataProvider + * + * @param int $categoryId + * @param string $exceptionMsg + * @return void */ - public function testDeleteSystemOrRoot() + public function testDeleteSystemOrRoot(int $categoryId, string $exceptionMsg): void { $this->expectException(\Exception::class); + $this->expectExceptionMessage($exceptionMsg); - $this->deleteCategory($this->modelId); + $this->deleteCategory($categoryId); } - public function deleteSystemOrRootDataProvider() + /** + * @return array + */ + public function deleteSystemOrRootDataProvider(): array { return [ - [Category::TREE_ROOT_ID], - [2] //Default root category + 'system_category' => [ + 'category_id' => Category::TREE_ROOT_ID, + 'exception_message' => $this->buildExceptionMessage(Category::TREE_ROOT_ID), + ], + 'root_category' => [ + 'category_id' => 2, + 'exception_message' => $this->buildExceptionMessage(2), + ], ]; } + /** + * Build response error message + * + * @param int $categoryId + * @return string + */ + private function buildExceptionMessage(int $categoryId): string + { + $translatedMsg = (string)__('Cannot delete category with id %1'); + + return sprintf('{"message":"%s","parameters":["%u"]}', $translatedMsg, $categoryId); + } + /** * @magentoApiDataFixture Magento/Catalog/_files/category.php */ From 14f3af27d67db2f807fa413fe013b15ce48857f9 Mon Sep 17 00:00:00 2001 From: SmVladyslav <vlatame.tsg@gmail.com> Date: Wed, 30 Dec 2020 14:12:45 +0200 Subject: [PATCH 334/346] MC-39470: issue with dynamicRows component --- .../base/web/js/dynamic-rows/dynamic-rows.js | 18 +++++++--- .../base/js/dynamic-rows/dynamic-rows.test.js | 33 +++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js index 0ac35df78e001..45dfaa40f87df 100644 --- a/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js +++ b/app/code/Magento/Ui/view/base/web/js/dynamic-rows/dynamic-rows.js @@ -620,15 +620,12 @@ define([ * @param {Array} data */ parsePagesData: function (data) { - var pages; - this.relatedData = this.deleteProperty ? _.filter(data, function (elem) { return elem && elem[this.deleteProperty] !== this.deleteValue; }, this) : data; - pages = Math.ceil(this.relatedData.length / this.pageSize) || 1; - this.pages(pages); + this._updatePagesQuantity(); }, /** @@ -885,6 +882,18 @@ define([ this._sort(); }, + /** + * Update number of pages. + * + * @private + * @return void + */ + _updatePagesQuantity: function () { + var pages = Math.ceil(this.relatedData.length / this.pageSize) || 1; + + this.pages(pages); + }, + /** * Reduce the number of pages * @@ -960,6 +969,7 @@ define([ reload: function () { this.clear(); this.initChildren(false, true); + this._updatePagesQuantity(); /* After change page size need to check existing current page */ this._reducePages(); diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/dynamic-rows/dynamic-rows.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/dynamic-rows/dynamic-rows.test.js index fc60fbb0bdccc..1101770b0faa2 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/dynamic-rows/dynamic-rows.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/dynamic-rows/dynamic-rows.test.js @@ -171,5 +171,38 @@ define([ }; expect(JSON.stringify(model.labels())).toEqual(JSON.stringify(result)); }); + + it('Check _updatePagesQuantity method call.', function () { + model._updatePagesQuantity = jasmine.createSpy(); + + model.reload(); + + expect(model._updatePagesQuantity).toHaveBeenCalled(); + }); + + it('Check number of pages is updated after reloading dynamic-rows.', function () { + model.pageSize = 1; + model.relatedData = [ + { + name: 'first' + }, + { + name: 'second' + }, + { + name: 'third' + } + ]; + + model.reload(); + expect(model.pages()).toEqual(3); + + model.currentPage(3); + model.pageSize = 2; + + model.reload(); + expect(model.pages()).toEqual(2); + expect(model.currentPage()).toEqual(2); + }); }); }); From 10fe506d9489296e9c4b27666d3c687c07b8ba57 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 30 Dec 2020 14:16:56 +0200 Subject: [PATCH 335/346] MC-39702: Create automated test for: "Visual swatch on the product page" --- .../Product/Renderer/ConfigurableTest.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php index c900d276c7864..111d0aa08f7f5 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php @@ -148,6 +148,32 @@ public function testGetJsonSwatchConfigUsedProductImage(): void ); } + /** + * @magentoDataFixture Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_image.php + * @return void + */ + public function testGetJsonSwatchConfigUsedWithSwatchImageType(): void + { + $this->updateAttributeUseProductImageFlag(); + $this->updateProductImage('simple_option_2', '/m/a/magento_image.jpg'); + $this->setSwatchImage('simple_option_2', '/m/a/magento_image.jpg'); + $expectedOptions = $this->getDefaultOptionsList(); + $expectedOptions['option 2']['value'] = $this->imageUrlBuilder->getUrl( + '/m/a/magento_image.jpg', + 'swatch_image_base' + ); + $expectedOptions['option 2']['thumb'] = $this->imageUrlBuilder->getUrl( + '/m/a/magento_image.jpg', + 'swatch_thumb_base' + ); + $this->assertOptionsData( + $this->serializer->unserialize($this->block->getJsonSwatchConfig()), + $expectedOptions, + ['swatch_input_type' => 'visual', 'use_product_image_for_swatch' => 1] + ); + } + /** * @magentoDataFixture Magento/Swatches/_files/configurable_product_with_visual_swatch_attribute.php * @return void @@ -249,4 +275,18 @@ private function updateProductImage(string $sku, string $imageName): void ->setCanSaveCustomOptions(true); $this->productResource->save($product); } + + /** + * Set swatch image for a Product. + * + * @param string $sku + * @param string $imageName + * @return void + */ + private function setSwatchImage(string $sku, string $imageName): void + { + $product = $this->productRepository->get($sku); + $product->setSwatchImage($imageName)->save($product); + } } + From 16826bd19568a4df154f2fc787e2a89d99a2e46a Mon Sep 17 00:00:00 2001 From: Roman Zhupanyn <roma.dj.elf@gmail.com> Date: Wed, 30 Dec 2020 15:01:03 +0200 Subject: [PATCH 336/346] MC-39687: Create automated test for: "Set backorders "Allow Qty Below 0" and check indexers" --- .../Model/Config/Backend/BackordersTest.php | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogInventory/Model/Config/Backend/BackordersTest.php diff --git a/dev/tests/integration/testsuite/Magento/CatalogInventory/Model/Config/Backend/BackordersTest.php b/dev/tests/integration/testsuite/Magento/CatalogInventory/Model/Config/Backend/BackordersTest.php new file mode 100644 index 0000000000000..279e45fc868cc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogInventory/Model/Config/Backend/BackordersTest.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogInventory\Model\Config\Backend; + +use Magento\CatalogInventory\Model\Configuration; +use Magento\CatalogInventory\Model\Indexer\Stock\Processor; +use Magento\CatalogInventory\Model\Stock; +use Magento\Config\Model\Config\BackendFactory; +use Magento\Framework\App\Config\MutableScopeConfigInterface; +use Magento\Framework\Indexer\StateInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Checks that the backorders config backend model is working correctly + */ +class BackordersTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Backorders */ + private $backorders; + + /** @var BackendFactory */ + private $backendFactory; + + /** @var MutableScopeConfigInterface */ + private $mutableConfig; + + /** @var Processor */ + private $stockIndexerProcessor; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->backendFactory = $this->objectManager->create(BackendFactory::class); + $this->backorders = $this->backendFactory->create(Backorders::class, [ + 'data' => [ + 'path' => Configuration::XML_PATH_BACKORDERS, + ] + ]); + $this->mutableConfig = $this->objectManager->get(MutableScopeConfigInterface::class); + $this->stockIndexerProcessor = $this->objectManager->get(Processor::class); + } + + /** + * @dataProvider afterSaveDataProvider + * @param int $value + * @param int $currentValue + * @param string $expectedIndexerStatus + * @magentoDbIsolation disabled + * @return void + */ + public function testAfterSave(int $value, int $currentValue, string $expectedIndexerStatus): void + { + $this->stockIndexerProcessor->reindexAll(); + $this->mutableConfig->setValue(Configuration::XML_PATH_BACKORDERS, $currentValue); + $this->backorders->setValue((string)$value); + $this->backorders->afterSave(); + + $this->assertEquals($expectedIndexerStatus, $this->stockIndexerProcessor->getIndexer()->getStatus()); + } + + /** + * Data provider for testAfterSave + * + * @return array + */ + public function afterSaveDataProvider(): array + { + return [ + 'set_backorders' => [ + 'value' => Stock::BACKORDERS_YES_NONOTIFY, + 'current_value' => Stock::BACKORDERS_NO, + 'expected_indexer_status' => StateInterface::STATUS_INVALID, + ], + 'unset_backorders' => [ + 'value' => Stock::BACKORDERS_NO, + 'current_value' => Stock::BACKORDERS_YES_NONOTIFY, + 'expected_indexer_status' => StateInterface::STATUS_INVALID, + ], + 'same_backorders' => [ + 'value' => Stock::BACKORDERS_YES_NONOTIFY, + 'current_value' => Stock::BACKORDERS_YES_NONOTIFY, + 'expected_indexer_status' => StateInterface::STATUS_VALID, + ], + ]; + } +} From 048ada376695b0df9b5d63ab4a321a8d7302477c Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 30 Dec 2020 15:24:22 +0200 Subject: [PATCH 337/346] MC-40068: Create automated test for: "Try to delete root category by API call" --- .../testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php index 8e0aff81cc3b8..2e8eedf96b0f8 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php @@ -224,7 +224,9 @@ private function buildExceptionMessage(int $categoryId): string { $translatedMsg = (string)__('Cannot delete category with id %1'); - return sprintf('{"message":"%s","parameters":["%u"]}', $translatedMsg, $categoryId); + return TESTS_WEB_API_ADAPTER === self::ADAPTER_REST + ? sprintf('{"message":"%s","parameters":["%u"]}', $translatedMsg, $categoryId) + : $translatedMsg; } /** From c50560110e4eb940f07566ad66915c5ee58de60b Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Wed, 30 Dec 2020 15:37:34 +0200 Subject: [PATCH 338/346] MC-39702: Create automated test for: "Visual swatch on the category page" --- .../Product/Renderer/ConfigurableTest.php | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php index 111d0aa08f7f5..5c5b1399caed8 100644 --- a/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/Swatches/Block/Product/Renderer/ConfigurableTest.php @@ -156,8 +156,7 @@ public function testGetJsonSwatchConfigUsedProductImage(): void public function testGetJsonSwatchConfigUsedWithSwatchImageType(): void { $this->updateAttributeUseProductImageFlag(); - $this->updateProductImage('simple_option_2', '/m/a/magento_image.jpg'); - $this->setSwatchImage('simple_option_2', '/m/a/magento_image.jpg'); + $this->updateProductImage('simple_option_2', '/m/a/magento_image.jpg', ['swatch_image']); $expectedOptions = $this->getDefaultOptionsList(); $expectedOptions['option 2']['value'] = $this->imageUrlBuilder->getUrl( '/m/a/magento_image.jpg', @@ -249,15 +248,16 @@ private function updateAttributeUseProductImageFlag(): void * * @param string $sku * @param string $imageName + * @param array $imageRoles * @return void */ - private function updateProductImage(string $sku, string $imageName): void - { + private function updateProductImage( + string $sku, + string $imageName, + array $imageRoles = ['image', 'small_image', 'thumbnail'] + ): void { $product = $this->productRepository->get($sku); $product->setStoreId(Store::DEFAULT_STORE_ID) - ->setImage($imageName) - ->setSmallImage($imageName) - ->setThumbnail($imageName) ->setData( 'media_gallery', [ @@ -273,20 +273,10 @@ private function updateProductImage(string $sku, string $imageName): void ] ) ->setCanSaveCustomOptions(true); - $this->productResource->save($product); - } + foreach ($imageRoles as $role) { + $product->setData($role, $imageName); + } - /** - * Set swatch image for a Product. - * - * @param string $sku - * @param string $imageName - * @return void - */ - private function setSwatchImage(string $sku, string $imageName): void - { - $product = $this->productRepository->get($sku); - $product->setSwatchImage($imageName)->save($product); + $this->productResource->save($product); } } - From 62bb82c0e93a8085f7a0d5f479ff225896c45385 Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Thu, 31 Dec 2020 11:54:45 +0200 Subject: [PATCH 339/346] MC-30104: When using MysqlMQ messages are always set to complete even if exception occurs --- .../MessageQueue/Model/ResourceModel/Lock.php | 48 ++++---- .../TestModuleMysqlMq/Model/Processor.php | 25 +++- .../TestModuleMysqlMq/etc/communication.xml | 1 + .../Magento/TestModuleMysqlMq/etc/queue.xml | 3 + .../TestModuleMysqlMq/etc/queue_consumer.xml | 1 + .../TestModuleMysqlMq/etc/queue_publisher.xml | 3 + .../TestModuleMysqlMq/etc/queue_topology.xml | 1 + .../MessageQueue/Model/ConsumerTest.php | 109 ++++++++++++++++++ .../Model/ResourceModel/LockTest.php | 28 +++++ 9 files changed, 193 insertions(+), 26 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/MessageQueue/Model/ConsumerTest.php create mode 100644 dev/tests/integration/testsuite/Magento/MessageQueue/Model/ResourceModel/LockTest.php diff --git a/app/code/Magento/MessageQueue/Model/ResourceModel/Lock.php b/app/code/Magento/MessageQueue/Model/ResourceModel/Lock.php index 16c02a7505664..00399e30e8b72 100644 --- a/app/code/Magento/MessageQueue/Model/ResourceModel/Lock.php +++ b/app/code/Magento/MessageQueue/Model/ResourceModel/Lock.php @@ -5,46 +5,52 @@ */ namespace Magento\MessageQueue\Model\ResourceModel; -use \Magento\Framework\MessageQueue\Lock\ReaderInterface; -use \Magento\Framework\MessageQueue\Lock\WriterInterface; +use DateInterval; +use DateTime; +use Magento\Framework\MessageQueue\Lock\ReaderInterface; +use Magento\Framework\MessageQueue\Lock\WriterInterface; +use Magento\Framework\MessageQueue\LockInterface; +use Magento\Framework\Model\ResourceModel\Db\AbstractDb; +use Magento\Framework\Model\ResourceModel\Db\Context; +use Magento\MessageQueue\Model\LockFactory; /** * Class Lock to handle database lock table db transactions. */ -class Lock extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb implements ReaderInterface, WriterInterface +class Lock extends AbstractDb implements ReaderInterface, WriterInterface { /**#@+ * Constants */ - const QUEUE_LOCK_TABLE = 'queue_lock'; + public const QUEUE_LOCK_TABLE = 'queue_lock'; /**#@-*/ /**#@-*/ private $dateTime; /** - * @var \Magento\MessageQueue\Model\LockFactory + * @var LockFactory */ private $lockFactory; /** - * @var integer + * @var int */ private $interval; /** * Initialize dependencies. * - * @param \Magento\Framework\Model\ResourceModel\Db\Context $context + * @param Context $context * @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime - * @param \Magento\MessageQueue\Model\LockFactory $lockFactory - * @param null $connectionName - * @param integer $interval + * @param LockFactory $lockFactory + * @param ?string $connectionName + * @param int $interval */ public function __construct( - \Magento\Framework\Model\ResourceModel\Db\Context $context, + Context $context, \Magento\Framework\Stdlib\DateTime\DateTime $dateTime, - \Magento\MessageQueue\Model\LockFactory $lockFactory, + LockFactory $lockFactory, $connectionName = null, $interval = 86400 ) { @@ -55,7 +61,7 @@ public function __construct( } /** - * {@inheritDoc} + * @inheritdoc */ protected function _construct() { @@ -63,9 +69,9 @@ protected function _construct() } /** - * {@inheritDoc} + * @inheritdoc */ - public function read(\Magento\Framework\MessageQueue\LockInterface $lock, $code) + public function read(LockInterface $lock, $code) { $object = $this->lockFactory->create(); $object->load($code, 'message_code'); @@ -75,23 +81,25 @@ public function read(\Magento\Framework\MessageQueue\LockInterface $lock, $code) } /** - * {@inheritDoc} + * @inheritdoc */ - public function saveLock(\Magento\Framework\MessageQueue\LockInterface $lock) + public function saveLock(LockInterface $lock) { $object = $this->lockFactory->create(); $object->setMessageCode($lock->getMessageCode()); $object->setCreatedAt($this->dateTime->gmtTimestamp()); $object->save(); + $lock->setId($object->getId()); + $lock->setCreatedAt($object->getCreatedAt()); } /** - * {@inheritDoc} + * @inheritdoc */ public function releaseOutdatedLocks() { - $date = (new \DateTime())->setTimestamp($this->dateTime->gmtTimestamp()); - $date->add(new \DateInterval('PT' . $this->interval . 'S')); + $date = (new DateTime())->setTimestamp($this->dateTime->gmtTimestamp()); + $date->add(new DateInterval('PT' . $this->interval . 'S')); $this->getConnection()->delete($this->getTable(self::QUEUE_LOCK_TABLE), ['created_at <= ?' => $date]); } } diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/Processor.php b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/Processor.php index fb6fd4c5c2802..3d2f722ccb60e 100644 --- a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/Processor.php +++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/Model/Processor.php @@ -5,13 +5,16 @@ */ namespace Magento\TestModuleMysqlMq\Model; +use LogicException; +use Magento\Framework\MessageQueue\ConnectionLostException; + /** * Test message processor is used by \Magento\MysqlMq\Model\PublisherConsumerTest */ class Processor { /** - * @param \Magento\TestModuleMysqlMq\Model\DataObject $message + * @param DataObject $message */ public function processMessage($message) { @@ -23,7 +26,7 @@ public function processMessage($message) } /** - * @param \Magento\TestModuleMysqlMq\Model\DataObject $message + * @param DataObject $message */ public function processObjectCreated($message) { @@ -35,7 +38,7 @@ public function processObjectCreated($message) } /** - * @param \Magento\TestModuleMysqlMq\Model\DataObject $message + * @param DataObject $message */ public function processCustomObjectCreated($message) { @@ -47,7 +50,7 @@ public function processCustomObjectCreated($message) } /** - * @param \Magento\TestModuleMysqlMq\Model\DataObject $message + * @param DataObject $message */ public function processObjectUpdated($message) { @@ -59,13 +62,23 @@ public function processObjectUpdated($message) } /** - * @param \Magento\TestModuleMysqlMq\Model\DataObject $message + * @param DataObject $message */ public function processMessageWithException($message) { file_put_contents($message->getOutputPath(), "Exception processing {$message->getEntityId()}"); - throw new \LogicException( + throw new LogicException( "Exception during message processing happened. Entity: {{$message->getEntityId()}}" ); } + + /** + * @throws ConnectionLostException + */ + public function processMessageWithConnectionException() + { + throw new ConnectionLostException( + "Connection exception during message processing happened." + ); + } } diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/communication.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/communication.xml index 4d6269dbb7920..1a5a5feb11324 100644 --- a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/communication.xml +++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/communication.xml @@ -7,6 +7,7 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd"> <topic name="demo.exception" request="Magento\TestModuleMysqlMq\Model\DataObject"/> + <topic name="demo.connection.exception" request="Magento\TestModuleMysqlMq\Model\DataObject"/> <topic name="test.schema.defined.by.method" schema="Magento\TestModuleMysqlMq\Model\DataObjectRepository::delayedOperation" is_synchronous="false"/> <topic name="demo.object.created" request="Magento\TestModuleMysqlMq\Model\DataObject"/> <topic name="demo.object.updated" request="Magento\TestModuleMysqlMq\Model\DataObject"/> diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue.xml index 362237c0c5e62..c879b271c6651 100644 --- a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue.xml +++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue.xml @@ -9,6 +9,9 @@ <broker topic="demo.exception" type="db" exchange="magento"> <queue consumer="demoConsumerWithException" name="queue-exception" handler="Magento\TestModuleMysqlMq\Model\Processor::processMessageWithException"/> </broker> + <broker topic="demo.connection.exception" type="db" exchange="magento"> + <queue consumer="demoConsumerWithConnectionException" name="queue-connection-exception" handler="Magento\TestModuleMysqlMq\Model\Processor::processMessageWithConnectionException"/> + </broker> <broker topic="test.schema.defined.by.method" type="db" exchange="magento"> <queue consumer="delayedOperationConsumer" name="demo-queue-6" handler="Magento\TestModuleMysqlMq\Model\DataObjectRepository::delayedOperation"/> </broker> diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_consumer.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_consumer.xml index bb495a123a05d..6a3916a23b43b 100644 --- a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_consumer.xml +++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_consumer.xml @@ -10,5 +10,6 @@ <consumer name="demoConsumerQueueTwo" queue="queue-updated" connection="db" handler="Magento\TestModuleMysqlMq\Model\Processor::processObjectUpdated"/> <consumer name="demoConsumerQueueThree" queue="queue-custom-created" connection="db" handler="Magento\TestModuleMysqlMq\Model\Processor::processCustomObjectCreated"/> <consumer name="demoConsumerWithException" queue="queue-exception" connection="db" handler="Magento\TestModuleMysqlMq\Model\Processor::processMessageWithException"/> + <consumer name="demoConsumerWithConnectionException" queue="queue-connection-exception" connection="db" handler="Magento\TestModuleMysqlMq\Model\Processor::processMessageWithConnectionException"/> <consumer name="delayedOperationConsumer" queue="demo-queue-6" connection="db" handler="Magento\TestModuleMysqlMq\Model\DataObjectRepository::delayedOperation"/> </config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_publisher.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_publisher.xml index a665e10ef5f14..639503a936cb5 100644 --- a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_publisher.xml +++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_publisher.xml @@ -9,6 +9,9 @@ <publisher topic="demo.exception"> <connection name="db" exchange="magento"/> </publisher> + <publisher topic="demo.connection.exception"> + <connection name="db" exchange="magento"/> + </publisher> <publisher topic="test.schema.defined.by.method"> <connection name="db" exchange="magento"/> </publisher> diff --git a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_topology.xml b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_topology.xml index 2df5485ee3447..3612438c37f4a 100644 --- a/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_topology.xml +++ b/dev/tests/integration/_files/Magento/TestModuleMysqlMq/etc/queue_topology.xml @@ -9,6 +9,7 @@ <exchange name="magento" type="topic" connection="db"> <binding id="demo.exception.consumer" topic="demo.exception" destination="queue-exception" destinationType="queue"/> + <binding id="demo.connection.exception.consumer" topic="demo.connection.exception" destination="queue-connection-exception" destinationType="queue"/> <binding id="test.schema.defined.by.method" topic="test.schema.defined.by.method" destination="demo-queue-6" destinationType="queue"/> <binding id="demo.object.created" topic="demo.object.created" destination="queue-created" destinationType="queue"/> <binding id="demo.object.updated" topic="demo.object.updated" destination="queue-updated" destinationType="queue"/> diff --git a/dev/tests/integration/testsuite/Magento/MessageQueue/Model/ConsumerTest.php b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/ConsumerTest.php new file mode 100644 index 0000000000000..a3515b07f1e0b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/ConsumerTest.php @@ -0,0 +1,109 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\MessageQueue\Model; + +use Magento\Framework\MessageQueue\Consumer; +use Magento\Framework\MessageQueue\ConsumerFactory; +use Magento\Framework\MessageQueue\EnvelopeFactory; +use Magento\Framework\MessageQueue\QueueInterface; +use Magento\MysqlMq\Model\QueueManagement; +use Magento\MysqlMq\Model\ResourceModel\Queue; +use Magento\TestFramework\ObjectManager; +use PHPUnit\Framework\TestCase; + +/** + * Tests the different cases of consumers running by Consumer processor + */ +class ConsumerTest extends TestCase +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var Consumer + */ + private $model; + + /** + * @var Queue + */ + private $queueResource; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + $this->objectManager = ObjectManager::getInstance(); + /** @var ConsumerFactory $factory */ + $factory = $this->objectManager->get(ConsumerFactory::class); + $this->model = $factory->get('demoConsumerWithConnectionException'); + $this->queueResource = $this->objectManager->get(Queue::class); + } + + /** + * Test if after connection exception and retry + * message doesn't have success status but still has status in progress + * + * @return void + */ + public function testRunWithException(): void + { + /** @var EnvelopeFactory $envelopFactory */ + $envelopFactory = $this->objectManager->get(EnvelopeFactory::class); + $messageBody = '{"name":"test"}'; + $topicName = 'demo.connection.exception'; + $queueName = 'queue-connection-exception'; + $envelope = $envelopFactory->create(['body' => $messageBody, 'properties' => ['topic_name' => $topicName]]); + /** @var QueueInterface $queue */ + $queue = $this->objectManager->create( + \Magento\MysqlMq\Model\Driver\Queue::class, + ['queueName' => $queueName] + ); + $queue->push($envelope); + $messages = $this->queueResource->getMessages($queueName, 1); + $envelope = $envelopFactory->create(['body' => $messageBody, 'properties' => $messages[0]]); + $this->model->process(1); + $queue->reject($envelope); + $this->model->process(1); + $message = $this->getLastMessage($queueName); + $this->assertEquals(QueueManagement::MESSAGE_STATUS_IN_PROGRESS, $message['status']); + } + + /** + * Return last message by queue name + * + * @param string $queueName + * @return array + */ + private function getLastMessage(string $queueName) + { + $connection = $this->queueResource->getConnection(); + $select = $connection->select() + ->from( + ['queue_message' => $this->queueResource->getTable('queue_message')], + [] + )->join( + ['queue_message_status' => $this->queueResource->getTable('queue_message_status')], + 'queue_message.id = queue_message_status.message_id', + [ + QueueManagement::MESSAGE_QUEUE_RELATION_ID => 'id', + QueueManagement::MESSAGE_STATUS => 'status', + ] + )->join( + ['queue' => $this->queueResource->getTable('queue')], + 'queue.id = queue_message_status.queue_id', + [QueueManagement::MESSAGE_QUEUE_NAME => 'name'] + )->where('queue.name = ?', $queueName) + ->order(['queue_message_status.id DESC']); + + return $connection->fetchRow($select); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MessageQueue/Model/ResourceModel/LockTest.php b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/ResourceModel/LockTest.php new file mode 100644 index 0000000000000..bede370db29c4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/ResourceModel/LockTest.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\MessageQueue\Model\ResourceModel; + +use Magento\Framework\MessageQueue\LockInterface; +use Magento\TestFramework\ObjectManager; +use PHPUnit\Framework\TestCase; + +/** + * Covers Lock resource model test cases + */ +class LockTest extends TestCase +{ + public function testSaveLock() + { + $objectManager = ObjectManager::getInstance(); + /** @var Lock $resourceModel */ + $resourceModel = $objectManager->get(Lock::class); + $lock = $objectManager->create(LockInterface::class); + $resourceModel->saveLock($lock); + self::assertNotEquals(null, $lock->getId()); + } +} From 79887430a29094e13dbdbc084a4ed8c06f19474e Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Wed, 30 Dec 2020 13:33:06 +0200 Subject: [PATCH 340/346] MC-30127: Product Price is mismatch in invoice and invoice PDF magento for Bundle Product 2.2.1 --- .../Model/Sales/Order/Pdf/Items/Invoice.php | 152 +++++--- .../Sales/Order/Pdf/Items/InvoiceTest.php | 352 ++++++++++++++++++ 2 files changed, 460 insertions(+), 44 deletions(-) create mode 100644 app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php index 64e9f56dd65bc..26d0fd274014c 100644 --- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php +++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php @@ -8,6 +8,7 @@ namespace Magento\Bundle\Model\Sales\Order\Pdf\Items; use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\DataObject; use Magento\Framework\Filesystem; use Magento\Framework\Filter\FilterManager; use Magento\Framework\Model\Context; @@ -69,34 +70,38 @@ public function __construct( } /** - * Draw item line + * Draw bundle product item line * * @return void - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function draw() { - $order = $this->getOrder(); - $item = $this->getItem(); - $pdf = $this->getPdf(); - $page = $this->getPage(); + $draw = $this->drawChildrenItems(); + $draw = $this->drawCustomOptions($draw); + $page = $this->getPdf()->drawLineBlocks($this->getPage(), $draw, ['table_header' => true]); + + $this->setPage($page); + } + + /** + * Draw bundle product children items + * + * @return array + */ + private function drawChildrenItems(): array + { $this->_setFontRegular(); - $items = $this->getChildren($item); $prevOptionId = ''; $drawItems = []; - - foreach ($items as $childItem) { - $line = []; - + $optionId = 0; + foreach ($this->getChildren($this->getItem()) as $childItem) { + $lines = []; + $index = array_key_last($lines) !== null ? array_key_last($lines) + 1 : 0; $attributes = $this->getSelectionAttributes($childItem); if (is_array($attributes)) { $optionId = $attributes['option_id']; - } else { - $optionId = 0; } if (!isset($drawItems[$optionId])) { @@ -104,15 +109,14 @@ public function draw() } if ($childItem->getOrderItem()->getParentItem() && $prevOptionId != $attributes['option_id']) { - $line[0] = [ + $lines[$index][] = [ 'font' => 'italic', 'text' => $this->string->split($attributes['option_label'], 45, true, true), 'feed' => 35, ]; - $drawItems[$optionId] = ['lines' => [$line], 'height' => 15]; - - $line = []; + $drawItems[$optionId] = ['height' => 15]; + $index++; $prevOptionId = $attributes['option_id']; } @@ -124,35 +128,97 @@ public function draw() $feed = 35; $name = $childItem->getName(); } - $line[] = ['text' => $this->string->split($name, 35, true, true), 'feed' => $feed]; + $lines[$index][] = ['text' => $this->string->split($name, 35, true, true), 'feed' => $feed]; - // draw SKUs - if (!$childItem->getOrderItem()->getParentItem()) { - $text = []; - foreach ($this->string->split($item->getSku(), 17) as $part) { - $text[] = $part; - } - $line[] = ['text' => $text, 'feed' => 255]; - } + $lines = $this->drawSkus($childItem, $lines); - // draw prices - if ($this->canShowPriceInfo($childItem)) { - $price = $order->formatPriceTxt($childItem->getPrice()); - $line[] = ['text' => $price, 'feed' => 395, 'font' => 'bold', 'align' => 'right']; - $line[] = ['text' => $childItem->getQty() * 1, 'feed' => 435, 'font' => 'bold']; + $lines = $this->drawPrices($childItem, $lines); + $drawItems[$optionId]['lines'] = $lines; + } - $tax = $order->formatPriceTxt($childItem->getTaxAmount()); - $line[] = ['text' => $tax, 'feed' => 495, 'font' => 'bold', 'align' => 'right']; + return $drawItems; + } - $row_total = $order->formatPriceTxt($childItem->getRowTotal()); - $line[] = ['text' => $row_total, 'feed' => 565, 'font' => 'bold', 'align' => 'right']; + /** + * Draw sku parts + * + * @param DataObject $childItem + * @param array $lines + * @return array + */ + private function drawSkus(DataObject $childItem, array $lines): array + { + $index = array_key_last($lines); + if (!$childItem->getOrderItem()->getParentItem()) { + $text = []; + foreach ($this->string->split($this->getItem()->getSku(), 17) as $part) { + $text[] = $part; } + $lines[$index][] = ['text' => $text, 'feed' => 255]; + } + + return $lines; + } - $drawItems[$optionId]['lines'][] = $line; + /** + * Draw prices for bundle product children items + * + * @param DataObject $childItem + * @param array $lines + * @return array + */ + private function drawPrices(DataObject $childItem, array $lines): array + { + $index = array_key_last($lines); + if ($this->canShowPriceInfo($childItem)) { + $lines[$index][] = ['text' => $childItem->getQty() * 1, 'feed' => 435, 'align' => 'right']; + + $tax = $this->getOrder()->formatPriceTxt($childItem->getTaxAmount()); + $lines[$index][] = ['text' => $tax, 'feed' => 495, 'font' => 'bold', 'align' => 'right']; + + $item = $this->getItem(); + $this->_item = $childItem; + $feedPrice = 380; + $feedSubtotal = $feedPrice + 185; + foreach ($this->getItemPricesForDisplay() as $priceData) { + if (isset($priceData['label'])) { + // draw Price label + $lines[$index][] = ['text' => $priceData['label'], 'feed' => $feedPrice, 'align' => 'right']; + // draw Subtotal label + $lines[$index][] = ['text' => $priceData['label'], 'feed' => $feedSubtotal, 'align' => 'right']; + $index++; + } + // draw Price + $lines[$index][] = [ + 'text' => $priceData['price'], + 'feed' => $feedPrice, + 'font' => 'bold', + 'align' => 'right', + ]; + // draw Subtotal + $lines[$index][] = [ + 'text' => $priceData['subtotal'], + 'feed' => $feedSubtotal, + 'font' => 'bold', + 'align' => 'right', + ]; + $index++; + } + $this->_item = $item; } - // custom options - $options = $item->getOrderItem()->getProductOptions(); + return $lines; + } + + /** + * Draw bundle product custom options + * + * @param array $draw + * @return array + */ + private function drawCustomOptions(array $draw): array + { + $options = $this->getItem()->getOrderItem()->getProductOptions(); if ($options && isset($options['options'])) { foreach ($options['options'] as $option) { $lines = []; @@ -180,12 +246,10 @@ public function draw() $lines[][] = ['text' => $text, 'feed' => 40]; } - $drawItems[] = ['lines' => $lines, 'height' => 15]; + $draw[] = ['lines' => $lines, 'height' => 15]; } } - $page = $pdf->drawLineBlocks($page, $drawItems, ['table_header' => true]); - - $this->setPage($page); + return $draw; } } diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php new file mode 100644 index 0000000000000..e93d231383820 --- /dev/null +++ b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php @@ -0,0 +1,352 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Bundle\Test\Unit\Model\Sales\Order\Pdf\Items; + +use Magento\Bundle\Model\Sales\Order\Pdf\Items\Invoice; +use Magento\Framework\Data\Collection\AbstractDb; +use Magento\Framework\DataObject; +use Magento\Framework\Filesystem; +use Magento\Framework\Filter\FilterManager; +use Magento\Framework\Model\Context; +use Magento\Framework\Model\ResourceModel\AbstractResource; +use Magento\Framework\Registry; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\Framework\Stdlib\StringUtils; +use Magento\Sales\Model\Order; +use Magento\Sales\Model\Order\Pdf\Invoice as InvoicePdf; +use Magento\Tax\Helper\Data; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Zend_Pdf_Page; + +/** + * Covers bundle order item invoice print logic + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class InvoiceTest extends TestCase +{ + /** + * @var Invoice|MockObject + */ + private $model; + + /** + * @var Data|MockObject + */ + private $taxDataMock; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + $contextMock = $this->createMock(Context::class); + $registryMock = $this->createMock(Registry::class); + $this->taxDataMock = $this->createMock(Data::class); + $directoryMock = $this->createMock(Filesystem\Directory\Read::class); + $directoryMock->expects($this->any())->method('getAbsolutePath')->willReturn(''); + $filesystemMock = $this->createMock(Filesystem::class); + $filesystemMock->expects($this->any())->method('getDirectoryRead')->willReturn($directoryMock); + $filterManagerMock = $this->createMock(FilterManager::class); + $stringUtilsMock = $this->createMock(StringUtils::class); + $stringUtilsMock->expects($this->any())->method('split')->willReturnArgument(0); + $resourceMock = $this->createMock(AbstractResource::class); + $collectionMock = $this->createMock(AbstractDb::class); + $serializerMock = $this->createMock(Json::class); + + $this->model = $this->getMockBuilder(Invoice::class) + ->setConstructorArgs( + [ + $contextMock, + $registryMock, + $this->taxDataMock, + $filesystemMock, + $filterManagerMock, + $stringUtilsMock, + $serializerMock, + $resourceMock, + $collectionMock, + [], + ] + ) + ->onlyMethods( + [ + '_setFontRegular', + 'getChildren', + 'isShipmentSeparately', + 'isChildCalculated', + 'getValueHtml', + 'getSelectionAttributes', + ] + ) + ->getMock(); + } + + /** + * @dataProvider invoiceDataProvider + * @param array $expected + * @param string $method + */ + public function testDrawPrice(array $expected, string $method): void + { + $this->taxDataMock->expects($this->any())->method($method)->willReturn(true); + $pageMock = $this->createMock(Zend_Pdf_Page::class); + $this->model->setPage($pageMock); + $pdfMock = $this->createMock(InvoicePdf::class); + $pdfMock->expects($this->any())->method('drawLineBlocks')->with( + $pageMock, + $expected, + ['table_header' => true] + )->willReturn($pageMock); + $this->model->setPdf($pdfMock); + + $this->prepareModel(); + $this->model->draw(); + } + + /** + * @return array[] + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function invoiceDataProvider(): array + { + return [ + 'display_both' => [ + 'expected' => [ + 1 => [ + 'height' => 15, + 'lines' => [ + [ + [ + 'text' => 'test option', + 'feed' => 35, + 'font' => 'italic', + + ], + ], + [ + [ + 'text' => 'Simple1', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 1.66, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => 'Excl. Tax:', + 'feed' => 380, + 'align' => 'right', + ], + [ + 'text' => 'Excl. Tax:', + 'feed' => 565, + 'align' => 'right', + ], + ], + [ + [ + 'text' => '10.00', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '20.00', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + [ + [ + 'text' => 'Incl. Tax:', + 'feed' => 380, + 'align' => 'right', + ], + [ + 'text' => 'Incl. Tax:', + 'feed' => 565, + 'align' => 'right', + ], + ], + [ + [ + 'text' => '10.83', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '21.66', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + ], + ], + ], + 'tax_mock_method' => 'displaySalesBothPrices', + ], + 'including_tax' => [ + 'expected' => [ + 1 => [ + 'height' => 15, + 'lines' => [ + [ + [ + 'text' => 'test option', + 'feed' => 35, + 'font' => 'italic', + + ], + ], + [ + [ + 'text' => 'Simple1', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 1.66, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.83', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '21.66', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + ], + ], + ], + 'tax_mock_method' => 'displaySalesPriceInclTax', + ], + 'excluding_tax' => [ + 'expected' => [ + 1 => [ + 'height' => 15, + 'lines' => [ + [ + [ + 'text' => 'test option', + 'feed' => 35, + 'font' => 'italic', + + ], + ], + [ + [ + 'text' => 'Simple1', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 1.66, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.00', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '20.00', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + ], + ], + ], + 'tax_mock_method' => 'displaySalesPriceExclTax', + ], + ]; + } + + /** + * Prepare invoice draw model for test execution + * + * @return void + */ + private function prepareModel(): void + { + $parentItem = new DataObject( + [ + 'sku' => 'bundle-simple', + 'name' => 'Bundle', + 'order_item' => new DataObject( + [ + 'product_options' => [], + ] + ), + ] + ); + $items = [ + new DataObject( + [ + 'name' => 'Simple1', + 'sku' => 'simple1', + 'price' => '10.00', + 'price_incl_tax' => '10.83', + 'row_total' => '20.00', + 'row_total_incl_tax' => '21.66', + 'qty' => '2', + 'tax_amount' => '1.66', + 'order_item' => new DataObject( + [ + 'parent_item' => $parentItem, + ] + ), + ] + ), + ]; + $orderMock = $this->createMock(Order::class); + + $this->model->expects($this->any())->method('getChildren')->willReturn($items); + $this->model->expects($this->any())->method('isShipmentSeparately')->willReturn(false); + $this->model->expects($this->any())->method('isChildCalculated')->willReturn(true); + $this->model->expects($this->any())->method('getValueHtml')->willReturn($items[0]->getName()); + $this->model->expects($this->any())->method('getSelectionAttributes')->willReturn( + ['option_id' => 1, 'option_label' => 'test option'] + ); + + $orderMock->expects($this->any())->method('formatPriceTxt')->willReturnArgument(0); + $this->model->setOrder($orderMock); + $this->model->setItem($parentItem); + } +} From 1ce3e1fe70b5c549ff519560dd7ada48f7a2034c Mon Sep 17 00:00:00 2001 From: Viktor Kopin <viktor.kopin@transoftgroup.com> Date: Thu, 31 Dec 2020 16:36:31 +0200 Subject: [PATCH 341/346] MC-30127: Product Price is mismatch in invoice and invoice PDF magento for Bundle Product 2.2.1 --- .../Model/Sales/Order/Pdf/Items/Invoice.php | 5 +- .../Sales/Order/Pdf/Items/InvoiceTest.php | 216 ++---------- .../Order/Pdf/Items/InvoiceTestProvider.php | 329 ++++++++++++++++++ 3 files changed, 355 insertions(+), 195 deletions(-) create mode 100644 app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTestProvider.php diff --git a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php index 26d0fd274014c..a7f0a70b45219 100644 --- a/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php +++ b/app/code/Magento/Bundle/Model/Sales/Order/Pdf/Items/Invoice.php @@ -96,8 +96,8 @@ private function drawChildrenItems(): array $prevOptionId = ''; $drawItems = []; $optionId = 0; + $lines = []; foreach ($this->getChildren($this->getItem()) as $childItem) { - $lines = []; $index = array_key_last($lines) !== null ? array_key_last($lines) + 1 : 0; $attributes = $this->getSelectionAttributes($childItem); if (is_array($attributes)) { @@ -115,7 +115,6 @@ private function drawChildrenItems(): array 'feed' => 35, ]; - $drawItems[$optionId] = ['height' => 15]; $index++; $prevOptionId = $attributes['option_id']; } @@ -133,8 +132,8 @@ private function drawChildrenItems(): array $lines = $this->drawSkus($childItem, $lines); $lines = $this->drawPrices($childItem, $lines); - $drawItems[$optionId]['lines'] = $lines; } + $drawItems[$optionId]['lines'] = $lines; return $drawItems; } diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php index e93d231383820..e5bf94241dbd9 100644 --- a/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php +++ b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTest.php @@ -88,7 +88,7 @@ protected function setUp(): void } /** - * @dataProvider invoiceDataProvider + * @dataProvider \Magento\Bundle\Test\Unit\Model\Sales\Order\Pdf\Items\InvoiceTestProvider::getData * @param array $expected * @param string $method */ @@ -109,195 +109,6 @@ public function testDrawPrice(array $expected, string $method): void $this->model->draw(); } - /** - * @return array[] - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function invoiceDataProvider(): array - { - return [ - 'display_both' => [ - 'expected' => [ - 1 => [ - 'height' => 15, - 'lines' => [ - [ - [ - 'text' => 'test option', - 'feed' => 35, - 'font' => 'italic', - - ], - ], - [ - [ - 'text' => 'Simple1', - 'feed' => 40, - ], - [ - 'text' => 2, - 'feed' => 435, - 'align' => 'right', - ], - [ - 'text' => 1.66, - 'feed' => 495, - 'font' => 'bold', - 'align' => 'right', - ], - [ - 'text' => 'Excl. Tax:', - 'feed' => 380, - 'align' => 'right', - ], - [ - 'text' => 'Excl. Tax:', - 'feed' => 565, - 'align' => 'right', - ], - ], - [ - [ - 'text' => '10.00', - 'feed' => 380, - 'font' => 'bold', - 'align' => 'right', - ], - [ - 'text' => '20.00', - 'feed' => 565, - 'font' => 'bold', - 'align' => 'right', - ], - ], - [ - [ - 'text' => 'Incl. Tax:', - 'feed' => 380, - 'align' => 'right', - ], - [ - 'text' => 'Incl. Tax:', - 'feed' => 565, - 'align' => 'right', - ], - ], - [ - [ - 'text' => '10.83', - 'feed' => 380, - 'font' => 'bold', - 'align' => 'right', - ], - [ - 'text' => '21.66', - 'feed' => 565, - 'font' => 'bold', - 'align' => 'right', - ], - ], - ], - ], - ], - 'tax_mock_method' => 'displaySalesBothPrices', - ], - 'including_tax' => [ - 'expected' => [ - 1 => [ - 'height' => 15, - 'lines' => [ - [ - [ - 'text' => 'test option', - 'feed' => 35, - 'font' => 'italic', - - ], - ], - [ - [ - 'text' => 'Simple1', - 'feed' => 40, - ], - [ - 'text' => 2, - 'feed' => 435, - 'align' => 'right', - ], - [ - 'text' => 1.66, - 'feed' => 495, - 'font' => 'bold', - 'align' => 'right', - ], - [ - 'text' => '10.83', - 'feed' => 380, - 'font' => 'bold', - 'align' => 'right', - ], - [ - 'text' => '21.66', - 'feed' => 565, - 'font' => 'bold', - 'align' => 'right', - ], - ], - ], - ], - ], - 'tax_mock_method' => 'displaySalesPriceInclTax', - ], - 'excluding_tax' => [ - 'expected' => [ - 1 => [ - 'height' => 15, - 'lines' => [ - [ - [ - 'text' => 'test option', - 'feed' => 35, - 'font' => 'italic', - - ], - ], - [ - [ - 'text' => 'Simple1', - 'feed' => 40, - ], - [ - 'text' => 2, - 'feed' => 435, - 'align' => 'right', - ], - [ - 'text' => 1.66, - 'feed' => 495, - 'font' => 'bold', - 'align' => 'right', - ], - [ - 'text' => '10.00', - 'feed' => 380, - 'font' => 'bold', - 'align' => 'right', - ], - [ - 'text' => '20.00', - 'feed' => 565, - 'font' => 'bold', - 'align' => 'right', - ], - ], - ], - ], - ], - 'tax_mock_method' => 'displaySalesPriceExclTax', - ], - ]; - } - /** * Prepare invoice draw model for test execution * @@ -334,16 +145,37 @@ private function prepareModel(): void ), ] ), + new DataObject( + [ + 'name' => 'Simple2', + 'sku' => 'simple2', + 'price' => '5.00', + 'price_incl_tax' => '5.41', + 'row_total' => '10.00', + 'row_total_incl_tax' => '10.83', + 'qty' => '2', + 'tax_amount' => '0.83', + 'order_item' => new DataObject( + [ + 'parent_item' => $parentItem, + ] + ), + ] + ), ]; $orderMock = $this->createMock(Order::class); $this->model->expects($this->any())->method('getChildren')->willReturn($items); $this->model->expects($this->any())->method('isShipmentSeparately')->willReturn(false); $this->model->expects($this->any())->method('isChildCalculated')->willReturn(true); - $this->model->expects($this->any())->method('getValueHtml')->willReturn($items[0]->getName()); - $this->model->expects($this->any())->method('getSelectionAttributes')->willReturn( + $this->model->expects($this->at(2))->method('getSelectionAttributes')->willReturn( ['option_id' => 1, 'option_label' => 'test option'] ); + $this->model->expects($this->at(3))->method('getValueHtml')->willReturn($items[0]->getName()); + $this->model->expects($this->at(5))->method('getSelectionAttributes')->willReturn( + ['option_id' => 1, 'option_label' => 'second option'] + ); + $this->model->expects($this->at(6))->method('getValueHtml')->willReturn($items[1]->getName()); $orderMock->expects($this->any())->method('formatPriceTxt')->willReturnArgument(0); $this->model->setOrder($orderMock); diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTestProvider.php b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTestProvider.php new file mode 100644 index 0000000000000..7de3d383d006e --- /dev/null +++ b/app/code/Magento/Bundle/Test/Unit/Model/Sales/Order/Pdf/Items/InvoiceTestProvider.php @@ -0,0 +1,329 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Bundle\Test\Unit\Model\Sales\Order\Pdf\Items; + +/** + * Data provider class for InvoiceTest class + */ +class InvoiceTestProvider +{ + /** + * Returns invoice test variations data + * + * @return array[] + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function getData(): array + { + return [ + 'display_both' => [ + 'expected' => [ + 1 => [ + 'height' => 15, + 'lines' => [ + [ + [ + 'text' => 'test option', + 'feed' => 35, + 'font' => 'italic', + + ], + ], + [ + [ + 'text' => 'Simple1', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 1.66, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => 'Excl. Tax:', + 'feed' => 380, + 'align' => 'right', + ], + [ + 'text' => 'Excl. Tax:', + 'feed' => 565, + 'align' => 'right', + ], + ], + [ + [ + 'text' => '10.00', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '20.00', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + [ + [ + 'text' => 'Incl. Tax:', + 'feed' => 380, + 'align' => 'right', + ], + [ + 'text' => 'Incl. Tax:', + 'feed' => 565, + 'align' => 'right', + ], + ], + [ + [ + 'text' => '10.83', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '21.66', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + [ + [ + 'text' => 'Simple2', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 0.83, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => 'Excl. Tax:', + 'feed' => 380, + 'align' => 'right', + ], + [ + 'text' => 'Excl. Tax:', + 'feed' => 565, + 'align' => 'right', + ], + ], + [ + [ + 'text' => '5.00', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.00', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + [ + [ + 'text' => 'Incl. Tax:', + 'feed' => 380, + 'align' => 'right', + ], + [ + 'text' => 'Incl. Tax:', + 'feed' => 565, + 'align' => 'right', + ], + ], + [ + [ + 'text' => '5.41', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.83', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + ], + ], + ], + 'tax_mock_method' => 'displaySalesBothPrices', + ], + 'including_tax' => [ + 'expected' => [ + 1 => [ + 'height' => 15, + 'lines' => [ + [ + [ + 'text' => 'test option', + 'feed' => 35, + 'font' => 'italic', + ], + ], + [ + [ + 'text' => 'Simple1', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 1.66, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.83', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '21.66', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + [ + [ + 'text' => 'Simple2', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 0.83, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '5.41', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.83', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + ], + ], + ], + 'tax_mock_method' => 'displaySalesPriceInclTax', + ], + 'excluding_tax' => [ + 'expected' => [ + 1 => [ + 'height' => 15, + 'lines' => [ + [ + [ + 'text' => 'test option', + 'feed' => 35, + 'font' => 'italic', + + ], + ], + [ + [ + 'text' => 'Simple1', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 1.66, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.00', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '20.00', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + [ + [ + 'text' => 'Simple2', + 'feed' => 40, + ], + [ + 'text' => 2, + 'feed' => 435, + 'align' => 'right', + ], + [ + 'text' => 0.83, + 'feed' => 495, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '5.00', + 'feed' => 380, + 'font' => 'bold', + 'align' => 'right', + ], + [ + 'text' => '10.00', + 'feed' => 565, + 'font' => 'bold', + 'align' => 'right', + ], + ], + ], + ], + ], + 'tax_mock_method' => 'displaySalesPriceExclTax', + ], + ]; + } +} From 245fc040700e534181cff1956688c77c17eb33d1 Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 4 Jan 2021 17:06:37 +0200 Subject: [PATCH 342/346] MC-40061: Create automated test for: "Subscribe to stock price alert" --- .../Product/Edit/Tab/Alerts/StockTest.php | 90 +++++++++++++++++++ .../Product/Form/Modifier/AlertsTest.php | 56 ++++++++++++ .../_files/product_alert_rollback.php | 33 +++++++ .../_files/stock_alert_on_second_website.php | 66 ++++++++++++++ ...stock_alert_on_second_website_rollback.php | 52 +++++++++++ 5 files changed, 297 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php create mode 100644 dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website.php create mode 100644 dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website_rollback.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php new file mode 100644 index 0000000000000..d03bc935bcd72 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php @@ -0,0 +1,90 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts; + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\View\LayoutInterface; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Check stock alert grid + * + * @see \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Alerts\Stock + * + * @magentoAppArea adminhtml + */ +class StockTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Stock */ + private $block; + + /** @var StoreManagerInterface */ + private $storeManager; + + /** @var ProductRepositoryInterface */ + private $productRepository; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->block = $this->objectManager->get(LayoutInterface::class)->createBlock(Stock::class); + $this->storeManager = $this->objectManager->get(StoreManagerInterface::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + } + + /** + * @dataProvider alertsDataProvider + * + * @magentoDbIsolation disabled + * @magentoDataFixture Magento/ProductAlert/_files/product_alert.php + * @magentoDataFixture Magento/ProductAlert/_files/stock_alert_on_second_website.php + * + * @param string $sku + * @param string $expectedEmail + * @param string|null $storeCode + * @return void + */ + public function testGridCollectionWIthStoreId(string $sku, string $expectedEmail, ?string $storeCode = null): void + { + $productId = (int)$this->productRepository->get($sku)->getId(); + $storeId = $storeCode ? (int)$this->storeManager->getStore($storeCode)->getId() : null; + $this->block->getRequest()->setParams(['id' => $productId, 'store' => $storeId]); + $collection = $this->block->getPreparedCollection(); + $this->assertCount(1, $collection); + $this->assertEquals($expectedEmail, $collection->getFirstItem()->getEmail()); + } + + /** + * @return array + */ + public function alertsDataProvider(): array + { + return [ + 'without_store_id_filter' => [ + 'product_sku' => 'simple', + 'expected_customer_emails' => 'customer@example.com', + ], + 'with_store_id_filter' => [ + 'product_sku' => 'simple_on_second_website', + 'expected_customer_emails' => 'customer_second_ws_with_addr@example.com', + 'store_code' => 'fixture_third_store', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php new file mode 100644 index 0000000000000..96ddc66c875b7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/AlertsTest.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Ui\DataProvider\Product\Form\Modifier; + +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; +use PHPUnit\Framework\TestCase; + +/** + * Alerts modifier test + * + * @see \Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Alerts + * + * @magentoAppArea adminhtml + */ +class AlertsTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var Alerts */ + private $stockAlertsModifier; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->stockAlertsModifier = $this->objectManager->get(Alerts::class); + } + + /** + * @magentoConfigFixture current_store catalog/productalert/allow_stock 1 + * + * @return void + */ + public function testModifyMeta(): void + { + $meta = $this->stockAlertsModifier->modifyMeta([]); + $this->assertArrayHasKey('alerts', $meta); + $content = $meta['alerts']['children'][Alerts::DATA_SCOPE_STOCK]['arguments']['data']['config']['content']; + $this->assertEquals( + 1, + Xpath::getElementsCountForXpath("//div[@data-grid-id='alertStock']", $content) + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php new file mode 100644 index 0000000000000..e9c4900ded341 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/product_alert_rollback.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Framework\Registry; +use Magento\ProductAlert\Model\StockFactory; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +$objectManager = Bootstrap::getObjectManager(); +/** @var StockFactory $stockFactory */ +$stockFactory = $objectManager->get(StockFactory::class); +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +$customer = $customerRepository->get('customer@example.com'); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +$stockAlert = $stockFactory->create(); +$stockAlert->deleteCustomer((int)$customer->getId()); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_rollback.php'); +Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple_rollback.php'); diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website.php new file mode 100644 index 0000000000000..b9d4c4b81f69b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\Data\ProductInterfaceFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Visibility; +use Magento\CatalogInventory\Api\Data\StockStatusInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\ProductAlert\Model\ResourceModel\Stock as StockResource; +use Magento\ProductAlert\Model\StockFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + +Resolver::getInstance()->requireDataFixture('Magento/Customer/_files/customer_for_second_website_with_address.php'); + +$objectManager = Bootstrap::getObjectManager(); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +$secondWebsite = $storeManager->getWebsite('test'); +/** @var ProductInterfaceFactory $productFactory */ +$productFactory = $objectManager->get(ProductInterfaceFactory::class); +/** @var ProductRepositoryInterface $peoductRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var StockFactory $stockFactory */ +$stockFactory = $objectManager->get(StockFactory::class); +/** @var StockResource $stockResource */ +$stockResource = $objectManager->get(StockResource::class); +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +$customer = $customerRepository->get('customer_second_ws_with_addr@example.com', (int)$secondWebsite->getId()); + + +$product = $productFactory->create(); +$product + ->setTypeId('simple') + ->setAttributeSetId(4) + ->setWebsiteIds([(int)$secondWebsite->getId()]) + ->setName('Simple Product2') + ->setSku('simple_on_second_website') + ->setPrice(10) + ->setMetaTitle('meta title2') + ->setMetaKeyword('meta keyword2') + ->setMetaDescription('meta description2') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData(['is_in_stock' => StockStatusInterface::STATUS_OUT_OF_STOCK]); + +$productRepository->save($product); + +$stockAlert = $stockFactory->create(); +$stockAlert->setCustomerId( + $customer->getId() +)->setProductId( + (int)$productRepository->get($product->getSku())->getId() +)->setWebsiteId( + (int)$secondWebsite->getId() +)->setStoreId( + (int)$storeManager->getStore('fixture_third_store')->getId() +); +$stockResource->save($stockAlert); diff --git a/dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website_rollback.php b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website_rollback.php new file mode 100644 index 0000000000000..0fa5f73a7927c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/ProductAlert/_files/stock_alert_on_second_website_rollback.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Registry; +use Magento\ProductAlert\Model\ResourceModel\Stock as StockResource; +use Magento\ProductAlert\Model\StockFactory; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Workaround\Override\Fixture\Resolver; + + +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $peoductRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var StockFactory $stockFactory */ +$stockFactory = $objectManager->get(StockFactory::class); +/** @var StockResource $stockResource */ +$stockResource = $objectManager->get(StockResource::class); +/** @var StoreManagerInterface $storeManager */ +$storeManager = $objectManager->get(StoreManagerInterface::class); +$secondWebsite = $storeManager->getWebsite('test'); +/** @var CustomerRepositoryInterface $customerRepository */ +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +$customer = $customerRepository->get('customer_second_ws_with_addr@example.com', (int)$secondWebsite->getId()); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + $productRepository->deleteById('simple_on_second_website'); +} catch (NoSuchEntityException $e) { + //already removed +} + + +$stockAlert = $stockFactory->create(); +$stockAlert->deleteCustomer((int)$customer->getId(), (int)$secondWebsite->getId()); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); + +Resolver::getInstance() + ->requireDataFixture('Magento/Customer/_files/customer_for_second_website_with_address_rollback.php'); From d866a0b69b35f7207f743d48ad9bcc2c3280f85c Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Mon, 4 Jan 2021 18:17:41 +0200 Subject: [PATCH 343/346] MC-40070: Create automated test for: "Try to save product with string type qty value" --- .../Product/Attribute/Backend/StockTest.php | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php new file mode 100644 index 0000000000000..24d5b668ac09c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/StockTest.php @@ -0,0 +1,62 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Product\Attribute\Backend; + +use Magento\Catalog\Api\Data\ProductInterfaceFactory; +use Magento\Catalog\Model\Product; +use Magento\Eav\Model\Config; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Test class for backend stock attribute model. + * + * @see \Magento\Catalog\Model\Product\Attribute\Backend\Stock + * + * @magentoAppArea adminhtml + */ +class StockTest extends TestCase +{ + /** @var ObjectManagerInterface */ + private $objectManager; + + /** @var ProductInterfaceFactory */ + private $productFactory; + + /** @var Stock */ + private $model; + + /** + * @inheritdoc + */ + protected function setUp(): void + { + parent::setUp(); + + $this->objectManager = Bootstrap::getObjectManager(); + $this->productFactory = $this->objectManager->get(ProductInterfaceFactory::class); + $this->model = $this->objectManager->get(Stock::class); + $this->model->setAttribute( + $this->objectManager->get(Config::class)->getAttribute(Product::ENTITY, 'quantity_and_stock_status') + ); + } + + /** + * @return void + */ + public function testValidate(): void + { + $this->expectException(LocalizedException::class); + $this->expectErrorMessage((string)__('Please enter a valid number in this field.')); + $product = $this->productFactory->create(); + $product->setQuantityAndStockStatus(['qty' => 'string']); + $this->model->validate($product); + } +} From f5932e2fe2abbd8d011c53cc886d57f5d6464f20 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 5 Jan 2021 08:30:55 +0200 Subject: [PATCH 344/346] MC-40277: Integration test failed \Magento\Catalog\Block\Product\View\Options\Type\DateTest::testToHtmlWithDropDown --- .../Catalog/Block/Product/View/Options/Type/DateTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php index 91a54d8fc13fa..d21fdf190c0b8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/View/Options/Type/DateTest.php @@ -20,6 +20,7 @@ /** * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class DateTest extends TestCase { @@ -96,9 +97,10 @@ protected function tearDown(): void } /** - * @magentoAppArea frontend * @param array $data * @param array $expected + * @magentoAppArea frontend + * @magentoConfigFixture current_store catalog/custom_options/year_range 2020,2030 * @dataProvider toHtmlWithDropDownDataProvider */ public function testToHtmlWithDropDown(array $data, array $expected): void @@ -108,11 +110,12 @@ public function testToHtmlWithDropDown(array $data, array $expected): void } /** - * @magentoAppArea frontend - * @magentoConfigFixture current_store catalog/custom_options/use_calendar 1 * @param array $data * @param array $expected * @param string|null $locale + * @magentoAppArea frontend + * @magentoConfigFixture current_store catalog/custom_options/use_calendar 1 + * @magentoConfigFixture current_store catalog/custom_options/year_range 2020,2030 * @dataProvider toHtmlWithCalendarDataProvider */ public function testToHtmlWithCalendar(array $data, array $expected, ?string $locale = null): void From 0292cb250ec6c9a436486b7e6d1e11c4e3a95286 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 5 Jan 2021 08:54:49 +0200 Subject: [PATCH 345/346] MC-40277: Integration test failed \Magento\Catalog\Block\Product\View\Options\Type\DateTest::testToHtmlWithDropDown --- .../CreateProductAttributeEntityDateTest.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml index d1f7adb8a902c..9d805b2cf7930 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/CreateProductAttributeEntityTest/CreateProductAttributeEntityDateTest.xml @@ -14,8 +14,8 @@ <title value="Admin should be able to create a Date product attribute"/> <description value="Admin should be able to create a Date product attribute"/> <severity value="BLOCKER"/> - <testCaseId value="MC-10895"/> - <group value="Catalog"/> + <testCaseId value="MC-26021"/> + <group value="catalog"/> <group value="mtf_migrated"/> </annotations> @@ -34,7 +34,7 @@ <!--Generate date for use as default value, needs to be MM/d/YYYY and mm/d/yy--> <generateDate date="now" format="m/j/Y" stepKey="generateDefaultDate"/> - <generateDate date="now" format="m/j/y" stepKey="generateDateCompressedFormat"/> + <generateDate date="now" format="n/j/y" stepKey="generateDateCompressedFormat"/> <!--Navigate to Stores > Attributes > Product.--> <actionGroup ref="AdminOpenProductAttributePageActionGroup" stepKey="goToProductAttributes"/> From 7a1e8a88f00ceb4ff689e591eeaaa06e62fb336b Mon Sep 17 00:00:00 2001 From: Yurii Sapiha <yurasapiga93@gmail.com> Date: Tue, 5 Jan 2021 12:35:05 +0200 Subject: [PATCH 346/346] MC-40061: Create automated test for: "Subscribe to stock price alert" --- .../Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php index d03bc935bcd72..b9ccfd6d52458 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Adminhtml/Product/Edit/Tab/Alerts/StockTest.php @@ -60,7 +60,7 @@ protected function setUp(): void * @param string|null $storeCode * @return void */ - public function testGridCollectionWIthStoreId(string $sku, string $expectedEmail, ?string $storeCode = null): void + public function testGridCollectionWithStoreId(string $sku, string $expectedEmail, ?string $storeCode = null): void { $productId = (int)$this->productRepository->get($sku)->getId(); $storeId = $storeCode ? (int)$this->storeManager->getStore($storeCode)->getId() : null;