From a6e14260c2ca7c1e070092963c56061730afaf6a Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Wed, 7 Feb 2024 18:35:30 +0200 Subject: [PATCH 01/23] ACP2E-2738: fix data conversion impacted by timezone --- app/code/Magento/Fedex/Model/Carrier.php | 6 +++--- app/code/Magento/Shipping/Block/Tracking/Popup.php | 2 +- .../view/frontend/templates/tracking/progress.phtml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index 5192d64b5882..36a8451812da 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -1567,7 +1567,7 @@ private function processTrackingDetails($trackInfo): array } if ($datetime) { - $result['shippeddate'] = gmdate('Y-m-d', $datetime->getTimestamp()); + $result['shippeddate'] = gmdate('Y-m-d H:i:s', $datetime->getTimestamp()); } } @@ -1586,7 +1586,7 @@ private function processTrackingDetails($trackInfo): array $datetime = $this->getDeliveryDateTime($trackInfo); if ($datetime) { - $result['deliverydate'] = gmdate('Y-m-d', $datetime->getTimestamp()); + $result['deliverydate'] = gmdate('Y-m-d H:i:s', $datetime->getTimestamp()); $result['deliverytime'] = gmdate('H:i:s', $datetime->getTimestamp()); } @@ -1699,7 +1699,7 @@ private function processTrackDetailsEvents(array $events): array $datetime = $this->parseDate(!empty($event['date']) ? $event['date'] : null); if ($datetime) { - $item['deliverydate'] = gmdate('Y-m-d', $datetime->getTimestamp()); + $item['deliverydate'] = gmdate('Y-m-d H:i:s', $datetime->getTimestamp()); $item['deliverytime'] = gmdate('H:i:s', $datetime->getTimestamp()); } diff --git a/app/code/Magento/Shipping/Block/Tracking/Popup.php b/app/code/Magento/Shipping/Block/Tracking/Popup.php index 1eb679bd8cc7..55752fa2a2f5 100644 --- a/app/code/Magento/Shipping/Block/Tracking/Popup.php +++ b/app/code/Magento/Shipping/Block/Tracking/Popup.php @@ -92,7 +92,7 @@ public function formatDeliveryDate($date) public function formatDeliveryTime($time, $date = null) { if (!empty($date)) { - $time = $date . ' ' . $time; + $time = $date; } $format = $this->_localeDate->getTimeFormat(\IntlDateFormatter::SHORT); diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml index e15c39367529..c82c4ba39f7a 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml @@ -22,7 +22,7 @@ $track = $block->getData('track'); getProgressdetail() as $detail) : ?> formatDeliveryDate($detail['deliverydate'] . ' ' . $detail['deliverytime']) : + $parentBlock->formatDeliveryDate($detail['deliverydate']) : ''); ?> formatDeliveryTime($detail['deliverytime'], $detail['deliverydate']) : From c5b0cda29b97a7f905b70269048bc7d7057fdede Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Thu, 8 Feb 2024 12:15:31 +0200 Subject: [PATCH 02/23] ACP2E-2738: fix static and unit tests errors --- .../Fedex/Test/Unit/Model/CarrierTest.php | 13 +++++---- .../templates/tracking/progress.phtml | 29 ++++++++++--------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php b/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php index f1dcc8f76d64..88b0720e00a4 100644 --- a/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php +++ b/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php @@ -650,6 +650,7 @@ public function testGetTrackingErrorResponse(): void */ public function getTrackResponse($shipTimeStamp, $expectedDate, $expectedTime): array { + $expectedDateTime = ($expectedDate ? date('Y-m-d', strtotime($expectedDate)) : null).'T'.$expectedTime; $trackResponse = '{"transactionId":"4d37cd0c-f4e8-449f-ac95-d4d3132f0572", "output":{"completeTrackResults":[{"trackingNumber":"122816215025810","trackResults":[{"trackingNumberInfo": {"trackingNumber":"122816215025810","trackingNumberUniqueId":"12013~122816215025810~FDEG","carrierCode":"FDXG"}, @@ -661,14 +662,14 @@ public function getTrackResponse($shipTimeStamp, $expectedDate, $expectedTime): "latestStatusDetail":{"code":"DL","derivedCode":"DL","statusByLocale":"Delivered","description":"Delivered", "scanLocation":{"city":"Norton","stateOrProvinceCode":"VA","countryCode":"US","residential":false, "countryName":"United States"}},"dateAndTimes":[{"type":"ACTUAL_DELIVERY","dateTime": - "'.$expectedDate.'T'.$expectedTime.'"},{"type":"ACTUAL_PICKUP","dateTime":"2016-08-01T00:00:00-06:00"}, + "'.$expectedDateTime.'"},{"type":"ACTUAL_PICKUP","dateTime":"2016-08-01T00:00:00-06:00"}, {"type":"SHIP","dateTime":"'.$shipTimeStamp.'"}],"availableImages":[{"type":"SIGNATURE_PROOF_OF_DELIVERY"}], "specialHandlings":[{"type":"DIRECT_SIGNATURE_REQUIRED","description":"Direct Signature Required", "paymentType":"OTHER"}],"packageDetails":{"packagingDescription":{"type":"YOUR_PACKAGING","description": "Package"},"physicalPackagingType":"PACKAGE","sequenceNumber":"1","count":"1","weightAndDimensions": {"weight":[{"value":"21.5","unit":"LB"},{"value":"9.75","unit":"KG"}],"dimensions":[{"length":22,"width":17, "height":10,"units":"IN"},{"length":55,"width":43,"height":25,"units":"CM"}]},"packageContent":[]}, - "shipmentDetails":{"possessionStatus":true},"scanEvents":[{"date":"'.$expectedDate.'T'.$expectedTime.'", + "shipmentDetails":{"possessionStatus":true},"scanEvents":[{"date":"'.$expectedDateTime.'", "eventType":"DL","eventDescription":"Delivered","exceptionCode":"","exceptionDescription":"","scanLocation": {"streetLines":[""],"city":"Norton","stateOrProvinceCode":"VA","postalCode":"24273","countryCode":"US", "residential":false,"countryName":"United States"},"locationType":"DELIVERY_LOCATION","derivedStatusCode":"DL", @@ -951,27 +952,27 @@ public function shipDateDataProvider(): array 'tracking1' => [ 'tracking1', 'shipTimestamp' => '2020-08-15T02:06:35+03:00', - 'expectedDate' => '2014-01-09', + 'expectedDate' => '2014-01-09 18:31:00', '18:31:00', 0, ], 'tracking1-again' => [ 'tracking1', 'shipTimestamp' => '2014-01-09T02:06:35+03:00', - 'expectedDate' => '2014-01-09', + 'expectedDate' => '2014-01-09 18:31:00', '18:31:00', 0, ], 'tracking2' => [ 'tracking2', 'shipTimestamp' => '2014-01-09T02:06:35+03:00', - 'expectedDate' => '2014-01-09', + 'expectedDate' => '2014-01-09 23:06:35', '23:06:35', ], 'tracking3' => [ 'tracking3', 'shipTimestamp' => '2014-01-09T14:06:35', - 'expectedDate' => '2014-01-09', + 'expectedDate' => '2014-01-09 18:31:00', '18:31:00', ], 'tracking4' => [ diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml index c82c4ba39f7a..97693d2ca736 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml @@ -4,39 +4,42 @@ * See COPYING.txt for license details. */ -/** @var $block \Magento\Framework\View\Element\Template */ +/** + * @var \Magento\Framework\View\Element\Template $block + * @var \Magento\Framework\Escaper $escaper + */ $parentBlock = $block->getParentBlock(); $track = $block->getData('track'); ?>
- - +
escapeHtml(__('Track history')) ?>
+ - - - - + + + + getProgressdetail() as $detail) : ?> - formatDeliveryDate($detail['deliverydate']) : ''); ?> formatDeliveryTime($detail['deliverytime'], $detail['deliverydate']) : ''); ?> - - - - From d9cf04a966e78a0d8560c5b1530d04c1e64bd03d Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Thu, 8 Feb 2024 15:19:33 +0200 Subject: [PATCH 03/23] ACP2E-2738: fix static tests errors --- .../view/frontend/templates/tracking/progress.phtml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml index 97693d2ca736..dd78d6cae41a 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml @@ -12,7 +12,8 @@ $parentBlock = $block->getParentBlock(); $track = $block->getData('track'); ?>
-
escapeHtml(__('Track history')) ?>
escapeHtml(__('Location')) ?>escapeHtml(__('Date')) ?>escapeHtml(__('Local Time')) ?>escapeHtml(__('Description')) ?>escapeHtml(__('Location')) ?>escapeHtml(__('Date')) ?>escapeHtml(__('Local Time')) ?>escapeHtml(__('Description')) ?>
- escapeHtml($detail['deliverylocation']) : '') ?> + + escapeHtml($detail['deliverylocation']) : '') ?> + + + escapeHtml($detail['activity']) : '') ?>
+
@@ -23,7 +24,7 @@ $track = $block->getData('track'); - getProgressdetail() as $detail) : ?> + getProgressdetail() as $detail): ?> formatDeliveryDate($detail['deliverydate']) : ''); ?> @@ -32,7 +33,8 @@ $track = $block->getData('track'); ''); ?> From ac031cbc2e248a951ae3241a0a1b6b580d2e98f0 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Fri, 9 Feb 2024 11:49:23 +0200 Subject: [PATCH 05/23] ACP2E-2738: new fix data conversion impacted by timezone --- app/code/Magento/Fedex/Model/Carrier.php | 6 +- .../Block/Tracking/PopupDeliveryDate.php | 2 +- .../Fedex/Test/Unit/Model/CarrierTest.php | 13 ++-- .../Block/Tracking/PopupDeliveryDateTest.php | 66 ++++++++++++++++++- .../Magento/Shipping/Block/Tracking/Popup.php | 2 +- .../templates/tracking/progress.phtml | 37 +++++------ 6 files changed, 90 insertions(+), 36 deletions(-) diff --git a/app/code/Magento/Fedex/Model/Carrier.php b/app/code/Magento/Fedex/Model/Carrier.php index 36a8451812da..5192d64b5882 100644 --- a/app/code/Magento/Fedex/Model/Carrier.php +++ b/app/code/Magento/Fedex/Model/Carrier.php @@ -1567,7 +1567,7 @@ private function processTrackingDetails($trackInfo): array } if ($datetime) { - $result['shippeddate'] = gmdate('Y-m-d H:i:s', $datetime->getTimestamp()); + $result['shippeddate'] = gmdate('Y-m-d', $datetime->getTimestamp()); } } @@ -1586,7 +1586,7 @@ private function processTrackingDetails($trackInfo): array $datetime = $this->getDeliveryDateTime($trackInfo); if ($datetime) { - $result['deliverydate'] = gmdate('Y-m-d H:i:s', $datetime->getTimestamp()); + $result['deliverydate'] = gmdate('Y-m-d', $datetime->getTimestamp()); $result['deliverytime'] = gmdate('H:i:s', $datetime->getTimestamp()); } @@ -1699,7 +1699,7 @@ private function processTrackDetailsEvents(array $events): array $datetime = $this->parseDate(!empty($event['date']) ? $event['date'] : null); if ($datetime) { - $item['deliverydate'] = gmdate('Y-m-d H:i:s', $datetime->getTimestamp()); + $item['deliverydate'] = gmdate('Y-m-d', $datetime->getTimestamp()); $item['deliverytime'] = gmdate('H:i:s', $datetime->getTimestamp()); } diff --git a/app/code/Magento/Fedex/Plugin/Block/Tracking/PopupDeliveryDate.php b/app/code/Magento/Fedex/Plugin/Block/Tracking/PopupDeliveryDate.php index e1597707f9d0..18064677c96c 100644 --- a/app/code/Magento/Fedex/Plugin/Block/Tracking/PopupDeliveryDate.php +++ b/app/code/Magento/Fedex/Plugin/Block/Tracking/PopupDeliveryDate.php @@ -28,7 +28,7 @@ class PopupDeliveryDate public function afterFormatDeliveryDateTime(Popup $subject, $result, $date, $time) { if ($this->getCarrier($subject) === Carrier::CODE) { - $result = $subject->formatDeliveryDate($date); + $result = $subject->formatDeliveryDate($date. ' ' . $time); } return $result; } diff --git a/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php b/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php index 88b0720e00a4..f1dcc8f76d64 100644 --- a/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php +++ b/app/code/Magento/Fedex/Test/Unit/Model/CarrierTest.php @@ -650,7 +650,6 @@ public function testGetTrackingErrorResponse(): void */ public function getTrackResponse($shipTimeStamp, $expectedDate, $expectedTime): array { - $expectedDateTime = ($expectedDate ? date('Y-m-d', strtotime($expectedDate)) : null).'T'.$expectedTime; $trackResponse = '{"transactionId":"4d37cd0c-f4e8-449f-ac95-d4d3132f0572", "output":{"completeTrackResults":[{"trackingNumber":"122816215025810","trackResults":[{"trackingNumberInfo": {"trackingNumber":"122816215025810","trackingNumberUniqueId":"12013~122816215025810~FDEG","carrierCode":"FDXG"}, @@ -662,14 +661,14 @@ public function getTrackResponse($shipTimeStamp, $expectedDate, $expectedTime): "latestStatusDetail":{"code":"DL","derivedCode":"DL","statusByLocale":"Delivered","description":"Delivered", "scanLocation":{"city":"Norton","stateOrProvinceCode":"VA","countryCode":"US","residential":false, "countryName":"United States"}},"dateAndTimes":[{"type":"ACTUAL_DELIVERY","dateTime": - "'.$expectedDateTime.'"},{"type":"ACTUAL_PICKUP","dateTime":"2016-08-01T00:00:00-06:00"}, + "'.$expectedDate.'T'.$expectedTime.'"},{"type":"ACTUAL_PICKUP","dateTime":"2016-08-01T00:00:00-06:00"}, {"type":"SHIP","dateTime":"'.$shipTimeStamp.'"}],"availableImages":[{"type":"SIGNATURE_PROOF_OF_DELIVERY"}], "specialHandlings":[{"type":"DIRECT_SIGNATURE_REQUIRED","description":"Direct Signature Required", "paymentType":"OTHER"}],"packageDetails":{"packagingDescription":{"type":"YOUR_PACKAGING","description": "Package"},"physicalPackagingType":"PACKAGE","sequenceNumber":"1","count":"1","weightAndDimensions": {"weight":[{"value":"21.5","unit":"LB"},{"value":"9.75","unit":"KG"}],"dimensions":[{"length":22,"width":17, "height":10,"units":"IN"},{"length":55,"width":43,"height":25,"units":"CM"}]},"packageContent":[]}, - "shipmentDetails":{"possessionStatus":true},"scanEvents":[{"date":"'.$expectedDateTime.'", + "shipmentDetails":{"possessionStatus":true},"scanEvents":[{"date":"'.$expectedDate.'T'.$expectedTime.'", "eventType":"DL","eventDescription":"Delivered","exceptionCode":"","exceptionDescription":"","scanLocation": {"streetLines":[""],"city":"Norton","stateOrProvinceCode":"VA","postalCode":"24273","countryCode":"US", "residential":false,"countryName":"United States"},"locationType":"DELIVERY_LOCATION","derivedStatusCode":"DL", @@ -952,27 +951,27 @@ public function shipDateDataProvider(): array 'tracking1' => [ 'tracking1', 'shipTimestamp' => '2020-08-15T02:06:35+03:00', - 'expectedDate' => '2014-01-09 18:31:00', + 'expectedDate' => '2014-01-09', '18:31:00', 0, ], 'tracking1-again' => [ 'tracking1', 'shipTimestamp' => '2014-01-09T02:06:35+03:00', - 'expectedDate' => '2014-01-09 18:31:00', + 'expectedDate' => '2014-01-09', '18:31:00', 0, ], 'tracking2' => [ 'tracking2', 'shipTimestamp' => '2014-01-09T02:06:35+03:00', - 'expectedDate' => '2014-01-09 23:06:35', + 'expectedDate' => '2014-01-09', '23:06:35', ], 'tracking3' => [ 'tracking3', 'shipTimestamp' => '2014-01-09T14:06:35', - 'expectedDate' => '2014-01-09 18:31:00', + 'expectedDate' => '2014-01-09', '18:31:00', ], 'tracking4' => [ diff --git a/app/code/Magento/Fedex/Test/Unit/Plugin/Block/Tracking/PopupDeliveryDateTest.php b/app/code/Magento/Fedex/Test/Unit/Plugin/Block/Tracking/PopupDeliveryDateTest.php index e34c1bf0eb82..6c04d0a255c7 100644 --- a/app/code/Magento/Fedex/Test/Unit/Plugin/Block/Tracking/PopupDeliveryDateTest.php +++ b/app/code/Magento/Fedex/Test/Unit/Plugin/Block/Tracking/PopupDeliveryDateTest.php @@ -21,9 +21,9 @@ */ class PopupDeliveryDateTest extends TestCase { - const STUB_CARRIER_CODE_NOT_FEDEX = 'not-fedex'; - const STUB_DELIVERY_DATE = '2020-02-02'; - const STUB_DELIVERY_TIME = '12:00'; + public const STUB_CARRIER_CODE_NOT_FEDEX = 'not-fedex'; + public const STUB_DELIVERY_DATE = '2020-02-02'; + public const STUB_DELIVERY_TIME = '12:00'; /** * @var MockObject|PopupDeliveryDate @@ -68,6 +68,30 @@ public function testAfterFormatDeliveryDateTimeWithFedexCarrier() $this->executeOriginalMethod(); } + /** + * Test the method with Fedex carrier with timezone impact + * @dataProvider getDates + */ + public function testAfterFormatDeliveryDateTimeWithFedexCarrierWithTimezone( + $date, + $currentTimezone, + $convertedTimezone, + $expected + ) { + $this->trackingStatusMock->expects($this::once()) + ->method('getCarrier') + ->willReturn(Carrier::CODE); + + $date = new \DateTime($date, new \DateTimeZone($currentTimezone)); + $date->setTimezone(new \DateTimeZone($convertedTimezone)); + $this->subjectMock->expects($this->once())->method('formatDeliveryDate') + ->willReturn($date->format('Y-m-d')); + + $result = $this->executeOriginalMethodWithTimezone(); + + $this->assertEquals($expected, $result); + } + /** * Test the method with a different carrier */ @@ -119,4 +143,40 @@ private function executeOriginalMethod() self::STUB_DELIVERY_TIME ); } + + /** + * Run plugin's original method taking into account timezone + */ + private function executeOriginalMethodWithTimezone() + { + return $this->plugin->afterFormatDeliveryDateTime( + $this->subjectMock, + 'Test Result', + self::STUB_DELIVERY_DATE, + '00:00:00' + ); + } + + /** + * Data provider for testAfterFormatDeliveryDateTimeWithFedexCarrierWithTimezone + * + * @return array[] + */ + public function getDates(): array + { + return [ + 'same day' => [ + 'date' => '2024-01-07 06:00:00', + 'current_timezone' => 'US/Eastern', + 'converted_timezone' => 'America/Chicago', + 'expected' => '2024-01-07' + ], + 'previous day' => [ + 'date' => '2024-01-07 00:00:00', + 'current_timezone' => 'US/Eastern', + 'converted_timezone' => 'America/Chicago', + 'expected' => '2024-01-06' + ] + ]; + } } diff --git a/app/code/Magento/Shipping/Block/Tracking/Popup.php b/app/code/Magento/Shipping/Block/Tracking/Popup.php index 55752fa2a2f5..1eb679bd8cc7 100644 --- a/app/code/Magento/Shipping/Block/Tracking/Popup.php +++ b/app/code/Magento/Shipping/Block/Tracking/Popup.php @@ -92,7 +92,7 @@ public function formatDeliveryDate($date) public function formatDeliveryTime($time, $date = null) { if (!empty($date)) { - $time = $date; + $time = $date . ' ' . $time; } $format = $this->_localeDate->getTimeFormat(\IntlDateFormatter::SHORT); diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml index f01061c8137c..e15c39367529 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml @@ -4,45 +4,40 @@ * See COPYING.txt for license details. */ -/** - * @var \Magento\Framework\View\Element\Template $block - * @var \Magento\Framework\Escaper $escaper - */ +/** @var $block \Magento\Framework\View\Element\Template */ $parentBlock = $block->getParentBlock(); $track = $block->getData('track'); ?>
-
escapeHtml(__('Track history')) ?>
- escapeHtml($detail['deliverylocation']) : '') ?> + escapeHtml($detail['deliverylocation']) : '') ?> From d9b069e6fc0aeae03560434f58eaa4f1f0688eb8 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Thu, 8 Feb 2024 17:14:42 +0200 Subject: [PATCH 04/23] ACP2E-2738: fix static tests errors --- .../Shipping/view/frontend/templates/tracking/progress.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml index dd78d6cae41a..f01061c8137c 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml @@ -42,7 +42,7 @@ $track = $block->getData('track'); - escapeHtml($detail['activity']) : '') ?> + escapeHtml($detail['activity']) : '') ?>
- +
escapeHtml(__('Track history')) ?>
+ - - - - + + + + - getProgressdetail() as $detail): ?> - formatDeliveryDate($detail['deliverydate']) : + getProgressdetail() as $detail) : ?> + formatDeliveryDate($detail['deliverydate'] . ' ' . $detail['deliverytime']) : ''); ?> formatDeliveryTime($detail['deliverytime'], $detail['deliverydate']) : ''); ?> - - - - From 3b8ff8f230bd43ae5ff542753c93282fb4ef4005 Mon Sep 17 00:00:00 2001 From: arnsaha Date: Thu, 15 Feb 2024 12:59:40 -0600 Subject: [PATCH 06/23] ACP2E-2855: Type Mismatch in Data Comparison when checking if data has changes - with test --- .../Magento/Framework/Model/AbstractModel.php | 123 ++++++++++++------ .../Model/Test/Unit/AbstractModelTest.php | 45 +++++++ 2 files changed, 126 insertions(+), 42 deletions(-) diff --git a/lib/internal/Magento/Framework/Model/AbstractModel.php b/lib/internal/Magento/Framework/Model/AbstractModel.php index ce6235f3a4b9..5beef7c4136d 100644 --- a/lib/internal/Magento/Framework/Model/AbstractModel.php +++ b/lib/internal/Magento/Framework/Model/AbstractModel.php @@ -5,11 +5,24 @@ */ namespace Magento\Framework\Model; +use Exception; use Laminas\Validator\ValidatorChain; use Laminas\Validator\ValidatorInterface; +use Magento\Framework\App\CacheInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\App\State; use Magento\Framework\DataObject; +use Magento\Framework\Event\ManagerInterface; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Message\Error; +use Magento\Framework\Model\ActionValidator\RemoveAction; +use Magento\Framework\Model\ResourceModel\AbstractResource; +use Magento\Framework\Model\ResourceModel\Db\AbstractDb; +use Magento\Framework\Data\Collection\AbstractDb as AbstractDbCollection; +use Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection; use Magento\Framework\Phrase; +use Magento\Framework\Registry; +use Psr\Log\LoggerInterface; /** * Abstract model class @@ -71,12 +84,12 @@ abstract class AbstractModel extends DataObject /** * Resource model instance * - * @var \Magento\Framework\Model\ResourceModel\Db\AbstractDb + * @var AbstractDb */ protected $_resource; /** - * @var \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection + * @var AbstractCollection */ protected $_resourceCollection; @@ -129,34 +142,34 @@ abstract class AbstractModel extends DataObject /** * Application Event Dispatcher * - * @var \Magento\Framework\Event\ManagerInterface + * @var ManagerInterface */ protected $_eventManager; /** * Application Cache Manager * - * @var \Magento\Framework\App\CacheInterface + * @var CacheInterface */ protected $_cacheManager; /** - * @var \Magento\Framework\Registry + * @var Registry */ protected $_registry; /** - * @var \Psr\Log\LoggerInterface + * @var LoggerInterface */ protected $_logger; /** - * @var \Magento\Framework\App\State + * @var State */ protected $_appState; /** - * @var \Magento\Framework\Model\ActionValidator\RemoveAction + * @var RemoveAction */ protected $_actionValidator; @@ -168,18 +181,19 @@ abstract class AbstractModel extends DataObject protected $storedData = []; /** - * @param \Magento\Framework\Model\Context $context - * @param \Magento\Framework\Registry $registry - * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource - * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection + * @param Context $context + * @param Registry $registry + * @param AbstractResource|null $resource + * @param AbstractDbCollection|null $resourceCollection * @param array $data + * @throws LocalizedException */ 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, - array $data = [] + Context $context, + Registry $registry, + AbstractResource $resource = null, + AbstractDbCollection $resourceCollection = null, + array $data = [] ) { $this->_registry = $registry; $this->_appState = $context->getAppState(); @@ -214,6 +228,7 @@ protected function _construct() //phpcs:ignore Magento2.CodeAnalysis.EmptyBlock * * @param string $resourceModel * @return void + * @throws LocalizedException */ protected function _init($resourceModel) { @@ -252,11 +267,11 @@ public function __sleep() */ public function __wakeup() { - $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); - $this->_registry = $objectManager->get(\Magento\Framework\Registry::class); + $objectManager = ObjectManager::getInstance(); + $this->_registry = $objectManager->get(Registry::class); - $context = $objectManager->get(\Magento\Framework\Model\Context::class); - if ($context instanceof \Magento\Framework\Model\Context) { + $context = $objectManager->get(Context::class); + if ($context instanceof Context) { $this->_appState = $context->getAppState(); $this->_eventManager = $context->getEventDispatcher(); $this->_cacheManager = $context->getCacheManager(); @@ -357,6 +372,7 @@ public function setData($key, $value = null) } $this->_data = $key; } else { + $this->checkAndConvertNumericValue($key, $value); if (!array_key_exists($key, $this->_data) || $this->_data[$key] !== $value) { $this->_hasDataChanges = true; } @@ -470,19 +486,19 @@ protected function _setResourceModel($resourceName, $collectionName = null) /** * Get resource instance * - * @throws \Magento\Framework\Exception\LocalizedException - * @return \Magento\Framework\Model\ResourceModel\Db\AbstractDb + * @return AbstractDb + * @throws LocalizedException * @deprecated 101.0.0 because resource models should be used directly * @see we don't recommend this approach anymore */ protected function _getResource() { if (empty($this->_resourceName) && empty($this->_resource)) { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase('The resource isn\'t set.') + throw new LocalizedException( + new Phrase('The resource isn\'t set.') ); } - return $this->_resource ?: \Magento\Framework\App\ObjectManager::getInstance()->get($this->_resourceName); + return $this->_resource ?: ObjectManager::getInstance()->get($this->_resourceName); } /** @@ -499,20 +515,20 @@ public function getResourceName() * Get collection instance * * @TODO MAGETWO-23541: Incorrect dependencies between Model\AbstractModel and Data\Collection\Db from Framework - * @throws \Magento\Framework\Exception\LocalizedException - * @return \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection + * @throws LocalizedException + * @return AbstractCollection * @deprecated 101.0.0 because collections should be used directly via factory * @see we don't recommend this approach anymore */ public function getResourceCollection() { if (empty($this->_resourceCollection) && empty($this->_collectionName)) { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase('Model collection resource name is not defined.') + throw new LocalizedException( + new Phrase('Model collection resource name is not defined.') ); } return !$this->_collectionName ? clone $this - ->_resourceCollection : \Magento\Framework\App\ObjectManager::getInstance() + ->_resourceCollection : ObjectManager::getInstance() ->create( $this->_collectionName ); @@ -522,9 +538,10 @@ public function getResourceCollection() * Retrieve collection instance * * @TODO MAGETWO-23541: Incorrect dependencies between Model\AbstractModel and Data\Collection\Db from Framework - * @return \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection - * @deprecated 101.0.0 because collections should be used directly via factory + * @return AbstractCollection + * @throws LocalizedException * @see we don't recommend this approach anymore + * @deprecated 101.0.0 because collections should be used directly via factory */ public function getCollection() { @@ -537,10 +554,11 @@ public function getCollection() * @param integer $modelId * @param null|string $field * @return $this + * @throws LocalizedException + * @see we don't recommend this approach anymore * @deprecated 100.1.0 because entities must not be responsible for their own loading. * Service contracts should persist entities. Use resource model "load" or collections to implement * service contract model loading operations. - * @see we don't recommend this approach anymore */ public function load($modelId, $field = null) { @@ -651,7 +669,7 @@ public function setHasDataChanges($flag) * Save object data * * @return $this - * @throws \Exception + * @throws Exception * * @deprecated 100.1.0 because entities must not be responsible for their own persistence. * Service contracts should persist entities. Use resource model "save" to implement @@ -726,7 +744,7 @@ public function validateBeforeSave() new Phrase(implode(PHP_EOL, $errors)) ); foreach ($errors as $errorMessage) { - $exception->addMessage(new \Magento\Framework\Message\Error($errorMessage)); + $exception->addMessage(new Error($errorMessage)); } throw $exception; } @@ -739,6 +757,7 @@ public function validateBeforeSave() * Returns FALSE, if no validation rules exist. * * @return ValidatorInterface|false + * @throws LocalizedException */ protected function _getValidatorBeforeSave() { @@ -782,7 +801,7 @@ protected function _createValidatorBeforeSave() */ private function getValidator(): ValidatorChain { - return \Magento\Framework\App\ObjectManager::getInstance()->create(ValidatorChain::class); + return ObjectManager::getInstance()->create(ValidatorChain::class); } /** @@ -852,7 +871,7 @@ public function afterSave() * Delete object from database * * @return $this - * @throws \Exception + * @throws Exception * @deprecated 100.1.0 because entities must not be responsible for their own deletion. * Service contracts should delete entities. Use resource model "delete" method to implement * service contract persistence operations. @@ -868,13 +887,13 @@ public function delete() * Processing object before delete data * * @return $this - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function beforeDelete() { if (!$this->_actionValidator->isAllowed($this)) { - throw new \Magento\Framework\Exception\LocalizedException( - new \Magento\Framework\Phrase('Delete operation is forbidden for current area') + throw new LocalizedException( + new Phrase('Delete operation is forbidden for current area') ); } @@ -913,7 +932,7 @@ public function afterDeleteCommit() /** * Retrieve model resource * - * @return \Magento\Framework\Model\ResourceModel\Db\AbstractDb + * @return AbstractDb * @deprecated 101.0.0 because resource models should be used directly * @see we don't recommend this approach anymore */ @@ -1010,4 +1029,24 @@ public function getEventPrefix() { return $this->_eventPrefix; } + + /** + * Check and Convert Numeric Value for Proper Type Matching + * + * @param mixed $key + * @param mixed $value + * @return void + */ + private function checkAndConvertNumericValue(mixed $key, mixed $value): void + { + if (array_key_exists($key, $this->_data) && is_numeric($this->_data[$key]) + && $value != null + ) { + if (is_int($value)) { + $this->_data[$key] = (int) $this->_data[$key]; + } elseif (is_float($value)) { + $this->_data[$key] = (float) $this->_data[$key]; + } + } + } } diff --git a/lib/internal/Magento/Framework/Model/Test/Unit/AbstractModelTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/AbstractModelTest.php index b01d9aa5f51e..250269b6ce94 100644 --- a/lib/internal/Magento/Framework/Model/Test/Unit/AbstractModelTest.php +++ b/lib/internal/Magento/Framework/Model/Test/Unit/AbstractModelTest.php @@ -190,4 +190,49 @@ public function testSetDataChanges() $this->model->setDataChanges(true); $this->assertTrue($this->model->hasDataChanges()); } + + /** + * Test case for checking setData function is working for all possible key value pairs + * + * @dataProvider getKeyValueDataPairs + */ + public function testSetDataWithDifferentKeyValuePairs( + array $data, + mixed $testKey, + mixed $testValue, + bool $hasDataChangedFor + ): void { + $this->model->setData($data); + $this->model->setOrigData(); + $this->model->setData($testKey, $testValue); + $this->assertEquals($data, $this->model->getOrigData()); + $this->assertEquals($hasDataChangedFor, $this->model->dataHasChangedFor($testKey)); + } + + /** + * Data provider for testSetDataWithDifferentKeyValuePairs + * + * @return array + */ + public function getKeyValueDataPairs(): array + { + return [ + 'when test data and compare data are string' => [['key' => 'value'], 'key', 'value', false], + 'when test data and compare data are different' => [['key' => 'value'], 'key', 10, true], + 'when test data string and compare data is null' => [['key' => 'value'], 'key', null, true], + 'when test data and compare data both null' => [['key' => null], 'key', null, false], + 'when test data empty string and compare data is null' => [['key' => ''], 'key', null, false], + 'when test data and compare data are empty string' => [['key' => ''], 'key', '', false], + 'when test data is null and compare data is empty string' => [['key' => null], 'key', '', false], + 'when test data and compare data are int' => [['key' => 1], 'key', 1, false], + 'when test data is int and compare data is float' => [['key' => 1.0], 'key', 1, false], + 'when test data is string and compare data is float' => [['key' => '1.0'], 'key', 1.0, false], + 'when test data is string and compare data is int' => [['key' => '1'], 'key', 1, false], + 'when test data is float and compare data is string' => [['key' => 1.0], 'key', '1.0', false], + 'when test data is int and compare data is string' => [['key' => 1], 'key', '1', false], + 'when test data and compare data are float' => [['key' => 1.0], 'key', 1.0, false], + 'when test data is 0 and compare data is null' => [['key' => 0], 'key', null, false], + 'when test data is null and compare data is 0' => [['key' => null], 'key', 0, false], + ]; + } } From 162f8c401e655c54073297d303a27cfa93469892 Mon Sep 17 00:00:00 2001 From: flowers Date: Mon, 26 Feb 2024 14:09:18 -0600 Subject: [PATCH 07/23] ACP2E-2729: [CLARIFICATION] Feature Request ADA Compliance --- app/design/frontend/Magento/blank/web/css/print.less | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/design/frontend/Magento/blank/web/css/print.less b/app/design/frontend/Magento/blank/web/css/print.less index ebfc6ce4300b..760859a709c5 100644 --- a/app/design/frontend/Magento/blank/web/css/print.less +++ b/app/design/frontend/Magento/blank/web/css/print.less @@ -76,18 +76,18 @@ p, h2, h3 { - orphans: 3; - widows: 3; + page-break-inside: avoid; } .block-content { - page-break-before: avoid; + break-before: avoid; } .block-title, h2, h3 { - page-break-after: avoid; + break-after: avoid; + page-break-inside: avoid; } .nav-toggle { From 8607f99f8e96738e746f0595cbb34d03129fda7f Mon Sep 17 00:00:00 2001 From: flowers Date: Mon, 26 Feb 2024 14:19:37 -0600 Subject: [PATCH 08/23] ACP2E-2729: [CLARIFICATION] Feature Request ADA Compliance --- app/design/frontend/Magento/blank/web/css/print.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/design/frontend/Magento/blank/web/css/print.less b/app/design/frontend/Magento/blank/web/css/print.less index 760859a709c5..a729af614ba8 100644 --- a/app/design/frontend/Magento/blank/web/css/print.less +++ b/app/design/frontend/Magento/blank/web/css/print.less @@ -76,7 +76,7 @@ p, h2, h3 { - page-break-inside: avoid; + break-inside: avoid; } .block-content { @@ -87,7 +87,7 @@ h2, h3 { break-after: avoid; - page-break-inside: avoid; + break-inside: avoid; } .nav-toggle { From 9a9b5aceed5c7904b1640343563f8aaeb07804f2 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Tue, 27 Feb 2024 18:19:17 +0200 Subject: [PATCH 09/23] ACP2E-2850: emulate store as to load correct agreements based on quote store id --- .../Model/Checkout/Plugin/GuestValidation.php | 80 +++++++++++++++---- .../Model/Checkout/Plugin/Validation.php | 43 +++++++--- .../CheckoutAgreements/Model/EmulateStore.php | 56 +++++++++++++ 3 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 app/code/Magento/CheckoutAgreements/Model/EmulateStore.php diff --git a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php index 95330c9d0138..fe8a05220f2e 100644 --- a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php +++ b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php @@ -6,7 +6,19 @@ namespace Magento\CheckoutAgreements\Model\Checkout\Plugin; +use Magento\Checkout\Api\AgreementsValidatorInterface; +use Magento\Checkout\Api\GuestPaymentInformationManagementInterface; +use Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface; use Magento\CheckoutAgreements\Model\AgreementsProvider; +use Magento\CheckoutAgreements\Model\EmulateStore; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Exception\CouldNotSaveException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\AddressInterface; +use Magento\Quote\Api\Data\PaymentInterface; +use Magento\Quote\Model\MaskedQuoteIdToQuoteId; +use Magento\Quote\Model\QuoteIdMask; use Magento\Store\Model\ScopeInterface; use Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter; @@ -40,62 +52,96 @@ class GuestValidation private $activeStoreAgreementsFilter; /** - * @param \Magento\Checkout\Api\AgreementsValidatorInterface $agreementsValidator - * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfiguration - * @param \Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface $checkoutAgreementsList + * @var MaskedQuoteIdToQuoteId + */ + private MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId; + + /** + * @var CartRepositoryInterface + */ + private CartRepositoryInterface $quoteRepository; + + /** + * @var EmulateStore + */ + private EmulateStore $emulateStore; + + /** + * @param AgreementsValidatorInterface $agreementsValidator + * @param ScopeConfigInterface $scopeConfiguration + * @param CheckoutAgreementsListInterface $checkoutAgreementsList * @param ActiveStoreAgreementsFilter $activeStoreAgreementsFilter + * @param MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId + * @param CartRepositoryInterface $quoteRepository + * @param EmulateStore $emulateStore */ public function __construct( \Magento\Checkout\Api\AgreementsValidatorInterface $agreementsValidator, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfiguration, \Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface $checkoutAgreementsList, - \Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter $activeStoreAgreementsFilter + \Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter $activeStoreAgreementsFilter, + MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId, + CartRepositoryInterface $quoteRepository, + EmulateStore $emulateStore ) { $this->agreementsValidator = $agreementsValidator; $this->scopeConfiguration = $scopeConfiguration; $this->checkoutAgreementsList = $checkoutAgreementsList; $this->activeStoreAgreementsFilter = $activeStoreAgreementsFilter; + $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; + $this->quoteRepository = $quoteRepository; + $this->emulateStore = $emulateStore; } /** * Validates agreements before save payment information and order placing. * - * @param \Magento\Checkout\Api\GuestPaymentInformationManagementInterface $subject + * @param GuestPaymentInformationManagementInterface $subject * @param string $cartId * @param string $email - * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod - * @param \Magento\Quote\Api\Data\AddressInterface|null $billingAddress - * @throws \Magento\Framework\Exception\CouldNotSaveException + * @param PaymentInterface $paymentMethod + * @param AddressInterface|null $billingAddress * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @throws CouldNotSaveException|NoSuchEntityException */ public function beforeSavePaymentInformationAndPlaceOrder( - \Magento\Checkout\Api\GuestPaymentInformationManagementInterface $subject, + GuestPaymentInformationManagementInterface $subject, $cartId, $email, - \Magento\Quote\Api\Data\PaymentInterface $paymentMethod, - \Magento\Quote\Api\Data\AddressInterface $billingAddress = null + PaymentInterface $paymentMethod, + AddressInterface $billingAddress = null ) { if ($this->isAgreementEnabled()) { - $this->validateAgreements($paymentMethod); + $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); + $quote = $this->quoteRepository->get($quoteId); + $storeId = $quote->getStoreId(); + $this->validateAgreements($paymentMethod, $storeId); } } /** * Validates agreements. * - * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod - * @throws \Magento\Framework\Exception\CouldNotSaveException + * @param PaymentInterface $paymentMethod + * @param int $storeId * @return void + * @throws CouldNotSaveException */ - private function validateAgreements(\Magento\Quote\Api\Data\PaymentInterface $paymentMethod) + private function validateAgreements(PaymentInterface $paymentMethod, int $storeId) { $agreements = $paymentMethod->getExtensionAttributes() === null ? [] : $paymentMethod->getExtensionAttributes()->getAgreementIds(); - if (!$this->agreementsValidator->isValid($agreements)) { - throw new \Magento\Framework\Exception\CouldNotSaveException( + $isValid = $this->emulateStore->execute( + $storeId, + $this->agreementsValidator->isValid(...), + [$agreements] + ); + + if (!$isValid) { + throw new CouldNotSaveException( __( "The order wasn't placed. " . "First, agree to the terms and conditions, then try placing your order again." diff --git a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php index ceb0240af1df..440bdbb8cce1 100644 --- a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php +++ b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php @@ -6,9 +6,15 @@ namespace Magento\CheckoutAgreements\Model\Checkout\Plugin; +use Magento\Checkout\Api\AgreementsValidatorInterface; +use Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface; use Magento\CheckoutAgreements\Model\AgreementsProvider; use Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter; +use Magento\CheckoutAgreements\Model\EmulateStore; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Exception\CouldNotSaveException; use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\PaymentInterface; use Magento\Store\Model\ScopeInterface; /** @@ -37,31 +43,37 @@ class Validation private $activeStoreAgreementsFilter; /** - * Quote repository. - * * @var \Magento\Quote\Api\CartRepositoryInterface */ private $quoteRepository; /** - * @param \Magento\Checkout\Api\AgreementsValidatorInterface $agreementsValidator - * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfiguration - * @param \Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface $checkoutAgreementsList + * @var EmulateStore + */ + private EmulateStore $emulateStore; + + /** + * @param AgreementsValidatorInterface $agreementsValidator + * @param ScopeConfigInterface $scopeConfiguration + * @param CheckoutAgreementsListInterface $checkoutAgreementsList * @param ActiveStoreAgreementsFilter $activeStoreAgreementsFilter * @param CartRepositoryInterface $quoteRepository + * @param EmulateStore $emulateStore */ public function __construct( \Magento\Checkout\Api\AgreementsValidatorInterface $agreementsValidator, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfiguration, \Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface $checkoutAgreementsList, \Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter $activeStoreAgreementsFilter, - CartRepositoryInterface $quoteRepository + CartRepositoryInterface $quoteRepository, + EmulateStore $emulateStore ) { $this->agreementsValidator = $agreementsValidator; $this->scopeConfiguration = $scopeConfiguration; $this->checkoutAgreementsList = $checkoutAgreementsList; $this->activeStoreAgreementsFilter = $activeStoreAgreementsFilter; $this->quoteRepository = $quoteRepository; + $this->emulateStore = $emulateStore; } /** @@ -82,24 +94,33 @@ public function beforeSavePaymentInformationAndPlaceOrder( \Magento\Quote\Api\Data\AddressInterface $billingAddress = null ) { if ($this->isAgreementEnabled()) { - $this->validateAgreements($paymentMethod); + $quote = $this->quoteRepository->get($cartId); + $storeId = $quote->getStoreId(); + $this->validateAgreements($paymentMethod, $storeId); } } /** * Validate agreements base on the payment method * - * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod - * @throws \Magento\Framework\Exception\CouldNotSaveException + * @param PaymentInterface $paymentMethod + * @param int $storeId * @return void + * @throws CouldNotSaveException */ - protected function validateAgreements(\Magento\Quote\Api\Data\PaymentInterface $paymentMethod) + private function validateAgreements(\Magento\Quote\Api\Data\PaymentInterface $paymentMethod, int $storeId) { $agreements = $paymentMethod->getExtensionAttributes() === null ? [] : $paymentMethod->getExtensionAttributes()->getAgreementIds(); - if (!$this->agreementsValidator->isValid($agreements)) { + $isValid = $this->emulateStore->execute( + $storeId, + $this->agreementsValidator->isValid(...), + [$agreements] + ); + + if (!$isValid) { throw new \Magento\Framework\Exception\CouldNotSaveException( __( "The order wasn't placed. " diff --git a/app/code/Magento/CheckoutAgreements/Model/EmulateStore.php b/app/code/Magento/CheckoutAgreements/Model/EmulateStore.php new file mode 100644 index 000000000000..6b94d1f63575 --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/Model/EmulateStore.php @@ -0,0 +1,56 @@ +storeManager->getStore()->getId(); + if ($currentStoreId !== $storeId) { + $this->storeManager->setCurrentStore($storeId); + } + $result = $callable(...$args); + if ($currentStoreId !== $storeId) { + $this->storeManager->setCurrentStore($currentStoreId); + } + return $result; + } +} From 9bc7d7bbda1883fbacf2ba3bfad747e5282d066c Mon Sep 17 00:00:00 2001 From: flowers Date: Tue, 27 Feb 2024 13:51:40 -0600 Subject: [PATCH 10/23] ACP2E-2729: [CLARIFICATION] Feature Request ADA Compliance --- app/design/frontend/Magento/blank/web/css/print.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/design/frontend/Magento/blank/web/css/print.less b/app/design/frontend/Magento/blank/web/css/print.less index a729af614ba8..444fb253b0b2 100644 --- a/app/design/frontend/Magento/blank/web/css/print.less +++ b/app/design/frontend/Magento/blank/web/css/print.less @@ -3,6 +3,7 @@ * See COPYING.txt for license details. */ +//@codingStandardsIgnoreStart @import 'source/lib/_lib.less'; // Global lib @import 'source/_theme.less'; // Theme overrides @import 'source/_variables.less'; // Local theme variables @@ -27,7 +28,6 @@ text-shadow: none !important; } - // Black prints faster:h5bp.com/s a, a:visited { text-decoration: underline !important; @@ -137,3 +137,4 @@ display: none !important; } } +//@codingStandardsIgnoreEnd From baa3c73cdeef7d9c31606fc9db53809b6a336732 Mon Sep 17 00:00:00 2001 From: flowers Date: Tue, 27 Feb 2024 14:52:54 -0600 Subject: [PATCH 11/23] ACP2E-2729: [CLARIFICATION] Feature Request ADA Compliance --- app/design/frontend/Magento/blank/web/css/print.less | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/design/frontend/Magento/blank/web/css/print.less b/app/design/frontend/Magento/blank/web/css/print.less index 444fb253b0b2..86cb405a566a 100644 --- a/app/design/frontend/Magento/blank/web/css/print.less +++ b/app/design/frontend/Magento/blank/web/css/print.less @@ -3,7 +3,10 @@ * See COPYING.txt for license details. */ -//@codingStandardsIgnoreStart +/** + * @codingStandardsIgnoreStart + */ + @import 'source/lib/_lib.less'; // Global lib @import 'source/_theme.less'; // Theme overrides @import 'source/_variables.less'; // Local theme variables @@ -137,4 +140,4 @@ display: none !important; } } -//@codingStandardsIgnoreEnd +// @codingStandardsIgnoreEnd From d61ae387b243562fbbffd1a697f1c8a2b21ebe35 Mon Sep 17 00:00:00 2001 From: flowers Date: Tue, 27 Feb 2024 16:58:29 -0600 Subject: [PATCH 12/23] ACP2E-2729: [CLARIFICATION] Feature Request ADA Compliance --- app/design/frontend/Magento/blank/web/css/print.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/design/frontend/Magento/blank/web/css/print.less b/app/design/frontend/Magento/blank/web/css/print.less index 86cb405a566a..f39f0288b409 100644 --- a/app/design/frontend/Magento/blank/web/css/print.less +++ b/app/design/frontend/Magento/blank/web/css/print.less @@ -13,6 +13,8 @@ @baseDir: '../'; // Default +// @codingStandardsIgnoreEnd + // Magento/blank .page-print { .logo { @@ -140,4 +142,3 @@ display: none !important; } } -// @codingStandardsIgnoreEnd From 84e2b496049abf5b5ecacca8af52dd5495e8d00b Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Wed, 28 Feb 2024 15:52:49 +0200 Subject: [PATCH 13/23] ACP2E-2850: fix static unit tests --- .../Checkout/Plugin/GuestValidationTest.php | 71 +++++++++++++++++-- .../Model/Checkout/Plugin/ValidationTest.php | 41 +++++++++-- 2 files changed, 100 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php index bb05d5636677..d279725bb566 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php @@ -13,11 +13,16 @@ use Magento\CheckoutAgreements\Model\AgreementsProvider; use Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter; use Magento\CheckoutAgreements\Model\Checkout\Plugin\GuestValidation; +use Magento\CheckoutAgreements\Model\EmulateStore; use Magento\Framework\Api\SearchCriteria; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\PaymentExtension; +use Magento\Quote\Api\Data\PaymentExtensionInterface; use Magento\Quote\Api\Data\PaymentInterface; +use Magento\Quote\Model\MaskedQuoteIdToQuoteId; +use Magento\Quote\Model\Quote; use Magento\Store\Model\ScopeInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\RuntimeException; @@ -73,6 +78,26 @@ class GuestValidationTest extends TestCase */ private $agreementsFilterMock; + /** + * @var Quote|MockObject + */ + private Quote|MockObject $quoteMock; + + /** + * @var MaskedQuoteIdToQuoteId|MockObject + */ + private MaskedQuoteIdToQuoteId|MockObject $maskedQuoteIdToQuoteIdMock; + + /** + * @var CartRepositoryInterface|MockObject + */ + private CartRepositoryInterface|MockObject $cartRepositoryMock; + + /** + * @var EmulateStore|MockObject + */ + private EmulateStore|MockObject $emulateStoreMock; + protected function setUp(): void { $this->agreementsValidatorMock = $this->getMockForAbstractClass(AgreementsValidatorInterface::class); @@ -87,18 +112,38 @@ protected function setUp(): void $this->agreementsFilterMock = $this->createMock( ActiveStoreAgreementsFilter::class ); + $this->quoteMock = $this->createMock(Quote::class); + $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteId::class); + $this->cartRepositoryMock = $this->createMock(CartRepositoryInterface::class); + $this->emulateStoreMock = $this->createMock(EmulateStore::class); + + $storeId = 1; + $this->quoteMock->expects($this->once()) + ->method('getStoreId') + ->willReturn($storeId); + $this->maskedQuoteIdToQuoteIdMock->expects($this->once()) + ->method('execute') + ->with('0CQwCntNHR4yN9P5PUAzbxatvDvBXOce') + ->willReturn(1000); + $this->cartRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->quoteMock); $this->model = new GuestValidation( $this->agreementsValidatorMock, $this->scopeConfigMock, $this->checkoutAgreementsListMock, - $this->agreementsFilterMock + $this->agreementsFilterMock, + $this->maskedQuoteIdToQuoteIdMock, + $this->cartRepositoryMock, + $this->emulateStoreMock ); } public function testBeforeSavePaymentInformationAndPlaceOrder() { - $cartId = '100'; + $storeId = 1; + $cartId = '0CQwCntNHR4yN9P5PUAzbxatvDvBXOce'; $email = 'email@example.com'; $agreements = [1, 2, 3]; $this->scopeConfigMock @@ -115,10 +160,15 @@ public function testBeforeSavePaymentInformationAndPlaceOrder() ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); - $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(true); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); + $this->emulateStoreMock->expects($this->once()) + ->method('execute') + ->with($storeId, $this->callback(function ($callback) { + return is_callable($callback); + })) + ->willReturn(true); $this->model->beforeSavePaymentInformationAndPlaceOrder( $this->subjectMock, $cartId, @@ -131,9 +181,16 @@ public function testBeforeSavePaymentInformationAndPlaceOrder() public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotValid() { $this->expectException('Magento\Framework\Exception\CouldNotSaveException'); - $cartId = 100; + $storeId = 1; + $cartId = '0CQwCntNHR4yN9P5PUAzbxatvDvBXOce'; $email = 'email@example.com'; $agreements = [1, 2, 3]; + $this->emulateStoreMock->expects($this->once()) + ->method('execute') + ->with($storeId, $this->callback(function ($callback) { + return is_callable($callback); + })) + ->willReturn(false); $this->scopeConfigMock ->expects($this->once()) ->method('isSetFlag') @@ -148,7 +205,6 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); - $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(false); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); @@ -172,9 +228,10 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali */ private function getPaymentExtension(): MockObject { - $mockBuilder = $this->getMockBuilder(PaymentExtension::class); + $mockBuilder = $this->getMockBuilder(PaymentExtensionInterface::class) + ->disableOriginalConstructor(); try { - $mockBuilder->addMethods(['getAgreementIds']); + $mockBuilder->onlyMethods(['getAgreementIds', 'setAgreementIds']); } catch (RuntimeException $e) { // Payment extension already generated. } diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php index 6aa3d6223009..7e707e031343 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php @@ -13,11 +13,13 @@ use Magento\CheckoutAgreements\Model\AgreementsProvider; use Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter; use Magento\CheckoutAgreements\Model\Checkout\Plugin\Validation; +use Magento\CheckoutAgreements\Model\EmulateStore; use Magento\Framework\Api\SearchCriteria; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\PaymentExtension; +use Magento\Quote\Api\Data\PaymentExtensionInterface; use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Model\Quote; use Magento\Store\Model\ScopeInterface; @@ -86,6 +88,11 @@ class ValidationTest extends TestCase */ private $quoteRepositoryMock; + /** + * @var EmulateStore|MockObject + */ + private EmulateStore|MockObject $emulateStoreMock; + protected function setUp(): void { $this->agreementsValidatorMock = $this->getMockForAbstractClass(AgreementsValidatorInterface::class); @@ -94,6 +101,7 @@ protected function setUp(): void $this->addressMock = $this->getMockForAbstractClass(AddressInterface::class); $this->quoteMock = $this->getMockBuilder(Quote::class) ->addMethods(['getIsMultiShipping']) + ->onlyMethods(['getStoreId']) ->disableOriginalConstructor() ->getMock(); $this->quoteRepositoryMock = $this->getMockForAbstractClass(CartRepositoryInterface::class); @@ -105,20 +113,37 @@ protected function setUp(): void $this->agreementsFilterMock = $this->createMock( ActiveStoreAgreementsFilter::class ); + $this->emulateStoreMock = $this->createMock(EmulateStore::class); + + $storeId = 1; + $this->quoteMock->expects($this->once()) + ->method('getStoreId') + ->willReturn($storeId); + $this->quoteRepositoryMock->expects($this->once()) + ->method('get') + ->willReturn($this->quoteMock); $this->model = new Validation( $this->agreementsValidatorMock, $this->scopeConfigMock, $this->checkoutAgreementsListMock, $this->agreementsFilterMock, - $this->quoteRepositoryMock + $this->quoteRepositoryMock, + $this->emulateStoreMock ); } public function testBeforeSavePaymentInformationAndPlaceOrder() { + $storeId = 1; $cartId = 100; $agreements = [1, 2, 3]; + $this->emulateStoreMock->expects($this->once()) + ->method('execute') + ->with($storeId, $this->callback(function ($callback) { + return is_callable($callback); + })) + ->willReturn(true); $this->scopeConfigMock ->expects($this->once()) ->method('isSetFlag') @@ -140,7 +165,6 @@ public function testBeforeSavePaymentInformationAndPlaceOrder() ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); - $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(true); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); @@ -155,8 +179,15 @@ public function testBeforeSavePaymentInformationAndPlaceOrder() public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotValid() { $this->expectException('Magento\Framework\Exception\CouldNotSaveException'); + $storeId = 1; $cartId = 100; $agreements = [1, 2, 3]; + $this->emulateStoreMock->expects($this->once()) + ->method('execute') + ->with($storeId, $this->callback(function ($callback) { + return is_callable($callback); + })) + ->willReturn(false); $this->scopeConfigMock ->expects($this->once()) ->method('isSetFlag') @@ -178,7 +209,6 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); - $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(false); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); @@ -201,9 +231,10 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali */ private function getPaymentExtension(): MockObject { - $mockBuilder = $this->getMockBuilder(PaymentExtension::class); + $mockBuilder = $this->getMockBuilder(PaymentExtensionInterface::class) + ->disableOriginalConstructor(); try { - $mockBuilder->addMethods(['getAgreementIds']); + $mockBuilder->onlyMethods(['getAgreementIds', 'setAgreementIds']); } catch (RuntimeException $e) { // Payment extension already generated. } From 4036a7a483047c7221495bc437e3da9ff1efec1a Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Wed, 28 Feb 2024 18:57:13 +0200 Subject: [PATCH 14/23] ACP2E-2850: fix static unit error --- .../Model/Checkout/Plugin/GuestValidation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php index fe8a05220f2e..49895e5060c0 100644 --- a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php +++ b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php @@ -18,7 +18,6 @@ use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteId; -use Magento\Quote\Model\QuoteIdMask; use Magento\Store\Model\ScopeInterface; use Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter; @@ -28,6 +27,8 @@ * Plugin that checks if checkout agreement enabled and validates all agreements. * Current plugin is duplicate from Magento\CheckoutAgreements\Model\Checkout\Plugin\Validation due to different * interfaces of payment information and makes check before processing of payment information. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class GuestValidation { From b6aa0d7906e7ecf139f20c22e068b8865a27b6fa Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Wed, 28 Feb 2024 20:33:50 +0200 Subject: [PATCH 15/23] ACP2E-2850: added unit test --- .../Test/Unit/Model/EmulateStoreTest.php | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php new file mode 100644 index 000000000000..9bc65e42a379 --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php @@ -0,0 +1,97 @@ +storeManager = $this->createMock(StoreManager::class); + $this->store = $this->getMockForAbstractClass(StoreInterface::class); + $this->emulateStore = new EmulateStore( + $this->storeManager + ); + } + + /** + * @param int $storeId + * @param int $currentStoreId + * @return void + * @throws NoSuchEntityException + * @dataProvider executeDataProvider + */ + public function testExecute(int $storeId, int $currentStoreId): void + { + $this->store->expects($this->once()) + ->method('getId') + ->willReturn($currentStoreId); + $this->storeManager->expects($this->once()) + ->method('getStore') + ->willReturn($this->store); + + if ($storeId !== $currentStoreId) { + $expected = [ + [$storeId], + [$currentStoreId] + ]; + $this->storeManager->expects($this->exactly(2)) + ->method('setCurrentStore') + ->willReturnCallback(function (...$args) use (&$expected) { + $expectedArgs = array_shift($expected); + $this->assertSame($expectedArgs, $args); + }); + } + + $this->emulateStore->execute($storeId, function () use ($currentStoreId) { + }, [1, 2, 3]); + } + + /** + * @return array[] + */ + public function executeDataProvider(): array + { + return [ + 'no-emulation' => ['storeId' => 1, 'currentStoreId' => 1], + 'emulation' => ['storeId' => 2, 'currentStoreId' => 1] + ]; + } +} From 4de50ead53e0fb134f873393f0f57aff5ed7a87b Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Thu, 29 Feb 2024 11:20:03 +0200 Subject: [PATCH 16/23] ACP2E-2850: fix static unit errors --- .../Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php | 2 +- .../Test/Unit/Model/Checkout/Plugin/ValidationTest.php | 2 +- .../CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php index d279725bb566..1fd81fa68592 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php @@ -231,7 +231,7 @@ private function getPaymentExtension(): MockObject $mockBuilder = $this->getMockBuilder(PaymentExtensionInterface::class) ->disableOriginalConstructor(); try { - $mockBuilder->onlyMethods(['getAgreementIds', 'setAgreementIds']); + $mockBuilder->addMethods(['getAgreementIds', 'setAgreementIds']); } catch (RuntimeException $e) { // Payment extension already generated. } diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php index 7e707e031343..3b9099661148 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php @@ -234,7 +234,7 @@ private function getPaymentExtension(): MockObject $mockBuilder = $this->getMockBuilder(PaymentExtensionInterface::class) ->disableOriginalConstructor(); try { - $mockBuilder->onlyMethods(['getAgreementIds', 'setAgreementIds']); + $mockBuilder->addMethods(['getAgreementIds', 'setAgreementIds']); } catch (RuntimeException $e) { // Payment extension already generated. } diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php index 9bc65e42a379..1f54d22641a3 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php @@ -80,7 +80,7 @@ public function testExecute(int $storeId, int $currentStoreId): void }); } - $this->emulateStore->execute($storeId, function () use ($currentStoreId) { + $this->emulateStore->execute($storeId, function () { }, [1, 2, 3]); } From 1119c2e617cbb520f54ed693e037741f952f69a1 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Thu, 29 Feb 2024 17:35:12 +0200 Subject: [PATCH 17/23] ACP2E-2857: fix saving of custom_attribute default_sort_by from rest api --- app/code/Magento/Catalog/etc/di.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index a13175fa78e9..88109981e827 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -739,7 +739,7 @@ string int[] Magento\CatalogInventory\Api\Data\StockItemInterface[] - string[] + string From 815619915dfa37233c293c2c06b3bbeba6404efb Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Fri, 1 Mar 2024 13:01:06 +0200 Subject: [PATCH 18/23] ACP2E-2850: refactoring based on CR comments --- .../Model/Checkout/Plugin/GuestValidation.php | 42 +++----- .../Model/Checkout/Plugin/Validation.php | 19 ++-- .../CheckoutAgreements/Model/EmulateStore.php | 56 ----------- .../Checkout/Plugin/GuestValidationTest.php | 44 ++++----- .../Model/Checkout/Plugin/ValidationTest.php | 35 ++++--- .../Test/Unit/Model/EmulateStoreTest.php | 97 ------------------- 6 files changed, 61 insertions(+), 232 deletions(-) delete mode 100644 app/code/Magento/CheckoutAgreements/Model/EmulateStore.php delete mode 100644 app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php diff --git a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php index 49895e5060c0..a9bb75089e81 100644 --- a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php +++ b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php @@ -10,14 +10,13 @@ use Magento\Checkout\Api\GuestPaymentInformationManagementInterface; use Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface; use Magento\CheckoutAgreements\Model\AgreementsProvider; -use Magento\CheckoutAgreements\Model\EmulateStore; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\NoSuchEntityException; -use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\PaymentInterface; -use Magento\Quote\Model\MaskedQuoteIdToQuoteId; +use Magento\Quote\Api\GuestCartRepositoryInterface; +use Magento\Store\Model\App\Emulation; use Magento\Store\Model\ScopeInterface; use Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter; @@ -53,45 +52,37 @@ class GuestValidation private $activeStoreAgreementsFilter; /** - * @var MaskedQuoteIdToQuoteId + * @var GuestCartRepositoryInterface */ - private MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId; + private GuestCartRepositoryInterface $quoteRepository; /** - * @var CartRepositoryInterface + * @var Emulation */ - private CartRepositoryInterface $quoteRepository; - - /** - * @var EmulateStore - */ - private EmulateStore $emulateStore; + private Emulation $storeEmulation; /** * @param AgreementsValidatorInterface $agreementsValidator * @param ScopeConfigInterface $scopeConfiguration * @param CheckoutAgreementsListInterface $checkoutAgreementsList * @param ActiveStoreAgreementsFilter $activeStoreAgreementsFilter - * @param MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId - * @param CartRepositoryInterface $quoteRepository - * @param EmulateStore $emulateStore + * @param GuestCartRepositoryInterface $quoteRepository + * @param Emulation $storeEmulation */ public function __construct( \Magento\Checkout\Api\AgreementsValidatorInterface $agreementsValidator, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfiguration, \Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface $checkoutAgreementsList, \Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter $activeStoreAgreementsFilter, - MaskedQuoteIdToQuoteId $maskedQuoteIdToQuoteId, - CartRepositoryInterface $quoteRepository, - EmulateStore $emulateStore + GuestCartRepositoryInterface $quoteRepository, + Emulation $storeEmulation ) { $this->agreementsValidator = $agreementsValidator; $this->scopeConfiguration = $scopeConfiguration; $this->checkoutAgreementsList = $checkoutAgreementsList; $this->activeStoreAgreementsFilter = $activeStoreAgreementsFilter; - $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->quoteRepository = $quoteRepository; - $this->emulateStore = $emulateStore; + $this->storeEmulation = $storeEmulation; } /** @@ -114,8 +105,7 @@ public function beforeSavePaymentInformationAndPlaceOrder( AddressInterface $billingAddress = null ) { if ($this->isAgreementEnabled()) { - $quoteId = $this->maskedQuoteIdToQuoteId->execute($cartId); - $quote = $this->quoteRepository->get($quoteId); + $quote = $this->quoteRepository->get($cartId); $storeId = $quote->getStoreId(); $this->validateAgreements($paymentMethod, $storeId); } @@ -135,11 +125,9 @@ private function validateAgreements(PaymentInterface $paymentMethod, int $storeI ? [] : $paymentMethod->getExtensionAttributes()->getAgreementIds(); - $isValid = $this->emulateStore->execute( - $storeId, - $this->agreementsValidator->isValid(...), - [$agreements] - ); + $this->storeEmulation->startEnvironmentEmulation($storeId); + $isValid = $this->agreementsValidator->isValid($agreements); + $this->storeEmulation->stopEnvironmentEmulation(); if (!$isValid) { throw new CouldNotSaveException( diff --git a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php index 440bdbb8cce1..4b3d3ec6ed70 100644 --- a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php +++ b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/Validation.php @@ -15,6 +15,7 @@ use Magento\Framework\Exception\CouldNotSaveException; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\PaymentInterface; +use Magento\Store\Model\App\Emulation; use Magento\Store\Model\ScopeInterface; /** @@ -48,9 +49,9 @@ class Validation private $quoteRepository; /** - * @var EmulateStore + * @var Emulation */ - private EmulateStore $emulateStore; + private Emulation $storeEmulation; /** * @param AgreementsValidatorInterface $agreementsValidator @@ -58,7 +59,7 @@ class Validation * @param CheckoutAgreementsListInterface $checkoutAgreementsList * @param ActiveStoreAgreementsFilter $activeStoreAgreementsFilter * @param CartRepositoryInterface $quoteRepository - * @param EmulateStore $emulateStore + * @param Emulation $storeEmulation */ public function __construct( \Magento\Checkout\Api\AgreementsValidatorInterface $agreementsValidator, @@ -66,14 +67,14 @@ public function __construct( \Magento\CheckoutAgreements\Api\CheckoutAgreementsListInterface $checkoutAgreementsList, \Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter $activeStoreAgreementsFilter, CartRepositoryInterface $quoteRepository, - EmulateStore $emulateStore + Emulation $storeEmulation ) { $this->agreementsValidator = $agreementsValidator; $this->scopeConfiguration = $scopeConfiguration; $this->checkoutAgreementsList = $checkoutAgreementsList; $this->activeStoreAgreementsFilter = $activeStoreAgreementsFilter; $this->quoteRepository = $quoteRepository; - $this->emulateStore = $emulateStore; + $this->storeEmulation = $storeEmulation; } /** @@ -114,11 +115,9 @@ private function validateAgreements(\Magento\Quote\Api\Data\PaymentInterface $pa ? [] : $paymentMethod->getExtensionAttributes()->getAgreementIds(); - $isValid = $this->emulateStore->execute( - $storeId, - $this->agreementsValidator->isValid(...), - [$agreements] - ); + $this->storeEmulation->startEnvironmentEmulation($storeId); + $isValid = $this->agreementsValidator->isValid($agreements); + $this->storeEmulation->stopEnvironmentEmulation(); if (!$isValid) { throw new \Magento\Framework\Exception\CouldNotSaveException( diff --git a/app/code/Magento/CheckoutAgreements/Model/EmulateStore.php b/app/code/Magento/CheckoutAgreements/Model/EmulateStore.php deleted file mode 100644 index 6b94d1f63575..000000000000 --- a/app/code/Magento/CheckoutAgreements/Model/EmulateStore.php +++ /dev/null @@ -1,56 +0,0 @@ -storeManager->getStore()->getId(); - if ($currentStoreId !== $storeId) { - $this->storeManager->setCurrentStore($storeId); - } - $result = $callable(...$args); - if ($currentStoreId !== $storeId) { - $this->storeManager->setCurrentStore($currentStoreId); - } - return $result; - } -} diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php index 1fd81fa68592..4944e41974fc 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/GuestValidationTest.php @@ -13,16 +13,16 @@ use Magento\CheckoutAgreements\Model\AgreementsProvider; use Magento\CheckoutAgreements\Model\Api\SearchCriteria\ActiveStoreAgreementsFilter; use Magento\CheckoutAgreements\Model\Checkout\Plugin\GuestValidation; -use Magento\CheckoutAgreements\Model\EmulateStore; use Magento\Framework\Api\SearchCriteria; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\AddressInterface; -use Magento\Quote\Api\Data\PaymentExtension; use Magento\Quote\Api\Data\PaymentExtensionInterface; use Magento\Quote\Api\Data\PaymentInterface; +use Magento\Quote\Api\GuestCartRepositoryInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteId; use Magento\Quote\Model\Quote; +use Magento\Store\Model\App\Emulation; use Magento\Store\Model\ScopeInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\RuntimeException; @@ -94,9 +94,9 @@ class GuestValidationTest extends TestCase private CartRepositoryInterface|MockObject $cartRepositoryMock; /** - * @var EmulateStore|MockObject + * @var Emulation|MockObject */ - private EmulateStore|MockObject $emulateStoreMock; + private Emulation|MockObject $storeEmulationMock; protected function setUp(): void { @@ -114,19 +114,16 @@ protected function setUp(): void ); $this->quoteMock = $this->createMock(Quote::class); $this->maskedQuoteIdToQuoteIdMock = $this->createMock(MaskedQuoteIdToQuoteId::class); - $this->cartRepositoryMock = $this->createMock(CartRepositoryInterface::class); - $this->emulateStoreMock = $this->createMock(EmulateStore::class); + $this->cartRepositoryMock = $this->createMock(GuestCartRepositoryInterface::class); + $this->storeEmulationMock = $this->createMock(Emulation::class); $storeId = 1; $this->quoteMock->expects($this->once()) ->method('getStoreId') ->willReturn($storeId); - $this->maskedQuoteIdToQuoteIdMock->expects($this->once()) - ->method('execute') - ->with('0CQwCntNHR4yN9P5PUAzbxatvDvBXOce') - ->willReturn(1000); $this->cartRepositoryMock->expects($this->once()) ->method('get') + ->with('0CQwCntNHR4yN9P5PUAzbxatvDvBXOce') ->willReturn($this->quoteMock); $this->model = new GuestValidation( @@ -134,9 +131,8 @@ protected function setUp(): void $this->scopeConfigMock, $this->checkoutAgreementsListMock, $this->agreementsFilterMock, - $this->maskedQuoteIdToQuoteIdMock, $this->cartRepositoryMock, - $this->emulateStoreMock + $this->storeEmulationMock ); } @@ -160,15 +156,15 @@ public function testBeforeSavePaymentInformationAndPlaceOrder() ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); + $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(true); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); - $this->emulateStoreMock->expects($this->once()) - ->method('execute') - ->with($storeId, $this->callback(function ($callback) { - return is_callable($callback); - })) - ->willReturn(true); + $this->storeEmulationMock->expects($this->once()) + ->method('startEnvironmentEmulation') + ->with($storeId); + $this->storeEmulationMock->expects($this->once()) + ->method('stopEnvironmentEmulation'); $this->model->beforeSavePaymentInformationAndPlaceOrder( $this->subjectMock, $cartId, @@ -185,12 +181,6 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali $cartId = '0CQwCntNHR4yN9P5PUAzbxatvDvBXOce'; $email = 'email@example.com'; $agreements = [1, 2, 3]; - $this->emulateStoreMock->expects($this->once()) - ->method('execute') - ->with($storeId, $this->callback(function ($callback) { - return is_callable($callback); - })) - ->willReturn(false); $this->scopeConfigMock ->expects($this->once()) ->method('isSetFlag') @@ -205,9 +195,15 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); + $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(false); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); + $this->storeEmulationMock->expects($this->once()) + ->method('startEnvironmentEmulation') + ->with($storeId); + $this->storeEmulationMock->expects($this->once()) + ->method('stopEnvironmentEmulation'); $this->model->beforeSavePaymentInformationAndPlaceOrder( $this->subjectMock, $cartId, diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php index 3b9099661148..8c68a575251f 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php +++ b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/Checkout/Plugin/ValidationTest.php @@ -18,10 +18,10 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\Data\AddressInterface; -use Magento\Quote\Api\Data\PaymentExtension; use Magento\Quote\Api\Data\PaymentExtensionInterface; use Magento\Quote\Api\Data\PaymentInterface; use Magento\Quote\Model\Quote; +use Magento\Store\Model\App\Emulation; use Magento\Store\Model\ScopeInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\RuntimeException; @@ -89,9 +89,9 @@ class ValidationTest extends TestCase private $quoteRepositoryMock; /** - * @var EmulateStore|MockObject + * @var Emulation|MockObject */ - private EmulateStore|MockObject $emulateStoreMock; + private Emulation|MockObject $storeEmulationMock; protected function setUp(): void { @@ -113,7 +113,7 @@ protected function setUp(): void $this->agreementsFilterMock = $this->createMock( ActiveStoreAgreementsFilter::class ); - $this->emulateStoreMock = $this->createMock(EmulateStore::class); + $this->storeEmulationMock = $this->createMock(Emulation::class); $storeId = 1; $this->quoteMock->expects($this->once()) @@ -129,7 +129,7 @@ protected function setUp(): void $this->checkoutAgreementsListMock, $this->agreementsFilterMock, $this->quoteRepositoryMock, - $this->emulateStoreMock + $this->storeEmulationMock ); } @@ -138,12 +138,6 @@ public function testBeforeSavePaymentInformationAndPlaceOrder() $storeId = 1; $cartId = 100; $agreements = [1, 2, 3]; - $this->emulateStoreMock->expects($this->once()) - ->method('execute') - ->with($storeId, $this->callback(function ($callback) { - return is_callable($callback); - })) - ->willReturn(true); $this->scopeConfigMock ->expects($this->once()) ->method('isSetFlag') @@ -165,9 +159,15 @@ public function testBeforeSavePaymentInformationAndPlaceOrder() ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); + $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(true); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); + $this->storeEmulationMock->expects($this->once()) + ->method('startEnvironmentEmulation') + ->with($storeId); + $this->storeEmulationMock->expects($this->once()) + ->method('stopEnvironmentEmulation'); $this->model->beforeSavePaymentInformationAndPlaceOrder( $this->subjectMock, $cartId, @@ -182,12 +182,6 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali $storeId = 1; $cartId = 100; $agreements = [1, 2, 3]; - $this->emulateStoreMock->expects($this->once()) - ->method('execute') - ->with($storeId, $this->callback(function ($callback) { - return is_callable($callback); - })) - ->willReturn(false); $this->scopeConfigMock ->expects($this->once()) ->method('isSetFlag') @@ -209,16 +203,21 @@ public function testBeforeSavePaymentInformationAndPlaceOrderIfAgreementsNotVali ->with($searchCriteriaMock) ->willReturn([1]); $this->extensionAttributesMock->expects($this->once())->method('getAgreementIds')->willReturn($agreements); + $this->agreementsValidatorMock->expects($this->once())->method('isValid')->with($agreements)->willReturn(false); $this->paymentMock->expects(static::atLeastOnce()) ->method('getExtensionAttributes') ->willReturn($this->extensionAttributesMock); + $this->storeEmulationMock->expects($this->once()) + ->method('startEnvironmentEmulation') + ->with($storeId); + $this->storeEmulationMock->expects($this->once()) + ->method('stopEnvironmentEmulation'); $this->model->beforeSavePaymentInformationAndPlaceOrder( $this->subjectMock, $cartId, $this->paymentMock, $this->addressMock ); - $this->expectExceptionMessage( "The order wasn't placed. First, agree to the terms and conditions, then try placing your order again." ); diff --git a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php b/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php deleted file mode 100644 index 1f54d22641a3..000000000000 --- a/app/code/Magento/CheckoutAgreements/Test/Unit/Model/EmulateStoreTest.php +++ /dev/null @@ -1,97 +0,0 @@ -storeManager = $this->createMock(StoreManager::class); - $this->store = $this->getMockForAbstractClass(StoreInterface::class); - $this->emulateStore = new EmulateStore( - $this->storeManager - ); - } - - /** - * @param int $storeId - * @param int $currentStoreId - * @return void - * @throws NoSuchEntityException - * @dataProvider executeDataProvider - */ - public function testExecute(int $storeId, int $currentStoreId): void - { - $this->store->expects($this->once()) - ->method('getId') - ->willReturn($currentStoreId); - $this->storeManager->expects($this->once()) - ->method('getStore') - ->willReturn($this->store); - - if ($storeId !== $currentStoreId) { - $expected = [ - [$storeId], - [$currentStoreId] - ]; - $this->storeManager->expects($this->exactly(2)) - ->method('setCurrentStore') - ->willReturnCallback(function (...$args) use (&$expected) { - $expectedArgs = array_shift($expected); - $this->assertSame($expectedArgs, $args); - }); - } - - $this->emulateStore->execute($storeId, function () { - }, [1, 2, 3]); - } - - /** - * @return array[] - */ - public function executeDataProvider(): array - { - return [ - 'no-emulation' => ['storeId' => 1, 'currentStoreId' => 1], - 'emulation' => ['storeId' => 2, 'currentStoreId' => 1] - ]; - } -} From 4586c1e83067f13ff7991a11928ac7c1e2bb46c6 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Fri, 1 Mar 2024 13:02:37 +0200 Subject: [PATCH 19/23] ACP2E-2850: refactoring based on CR comments --- .../Model/Checkout/Plugin/GuestValidation.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php index a9bb75089e81..f7bede315042 100644 --- a/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php +++ b/app/code/Magento/CheckoutAgreements/Model/Checkout/Plugin/GuestValidation.php @@ -26,8 +26,6 @@ * Plugin that checks if checkout agreement enabled and validates all agreements. * Current plugin is duplicate from Magento\CheckoutAgreements\Model\Checkout\Plugin\Validation due to different * interfaces of payment information and makes check before processing of payment information. - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class GuestValidation { From 4af113a0cb168aee3051a25a2275f826bb34afa2 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Fri, 1 Mar 2024 14:06:52 +0200 Subject: [PATCH 20/23] ACP2E-2857: fix integration failures --- app/code/Magento/Catalog/Test/Fixture/Category.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Test/Fixture/Category.php b/app/code/Magento/Catalog/Test/Fixture/Category.php index 4e3a2d67c3ae..df4e7f88384b 100644 --- a/app/code/Magento/Catalog/Test/Fixture/Category.php +++ b/app/code/Magento/Catalog/Test/Fixture/Category.php @@ -27,7 +27,7 @@ class Category implements RevertibleDataFixtureInterface 'include_in_menu' => true, 'available_sort_by' => [], 'custom_attributes' => [ - 'default_sort_by' => ['name'] + 'default_sort_by' => 'position' ], 'extension_attributes' => [], 'created_at' => null, From b04e9d2f5f5b1ac6d06b8f9f01ebbe62a4f62285 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Mon, 4 Mar 2024 13:23:20 +0200 Subject: [PATCH 21/23] ACP2E-2857: fix failing graphql requests --- .../Attribute/Backend/DefaultSortby.php | 21 +++++ .../Data/UpdateDefaultSortyByBackendType.php | 80 +++++++++++++++++++ app/code/Magento/Catalog/etc/di.xml | 3 +- 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Catalog/Model/Category/Attribute/Backend/DefaultSortby.php create mode 100644 app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultSortyByBackendType.php diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/DefaultSortby.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/DefaultSortby.php new file mode 100644 index 000000000000..7a10b7f876c8 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/DefaultSortby.php @@ -0,0 +1,21 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + $mediaBackendModel = \Magento\Catalog\Model\Category\Attribute\Backend\DefaultSortby::class; + /** @var CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + $categorySetup->updateAttribute( + 'catalog_category', + 'default_sort_by', + 'backend_model', + $mediaBackendModel + ); + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return []; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 88109981e827..e604b0223799 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -739,7 +739,8 @@ string int[] Magento\CatalogInventory\Api\Data\StockItemInterface[] - string + string[] + string From 3061b40ec7c66d679b4b62b122b2297ce0d2e393 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Mon, 4 Mar 2024 13:27:21 +0200 Subject: [PATCH 22/23] ACP2E-2857: update webapi test to test default_sort_by --- .../Magento/Catalog/Api/CategoryRepositoryTest.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 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 03a48259d120..e16f7d513fdb 100644 --- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/CategoryRepositoryTest.php @@ -269,12 +269,13 @@ public function testUpdate() $this->createdCategories = [$categoryId]; } - /** - * @magentoApiDataFixture Magento/Catalog/_files/category.php - */ + #[ + DataFixture(CategoryFixture::class, as: 'category') + ] public function testUpdateWithDefaultSortByAttribute() { - $categoryId = 333; + $category = $this->fixtures->get('category'); + $categoryId = $category->getId(); $categoryData = [ 'name' => 'Update Category Test With default_sort_by Attribute', 'is_active' => true, @@ -282,7 +283,7 @@ public function testUpdateWithDefaultSortByAttribute() 'custom_attributes' => [ [ 'attribute_code' => 'default_sort_by', - 'value' => ["name"], + 'value' => "price" ], ], ]; @@ -293,7 +294,7 @@ public function testUpdateWithDefaultSortByAttribute() $category = $model->load($categoryId); $this->assertTrue((bool)$category->getIsActive(), 'Category "is_active" must equal to true'); $this->assertEquals("Update Category Test With default_sort_by Attribute", $category->getName()); - $this->assertEquals("name", $category->getDefaultSortBy()); + $this->assertEquals("price", $category->getDefaultSortBy()); $this->createdCategories = [$categoryId]; } From 0b3406dbca6c73a30e1d5c7642c5f8bacde89d93 Mon Sep 17 00:00:00 2001 From: Alexandra Zota Date: Mon, 4 Mar 2024 15:22:59 +0200 Subject: [PATCH 23/23] ACP2E-2857: fix webapi, integration, static tests' errors --- .../Setup/Patch/Data/UpdateDefaultSortyByBackendType.php | 5 ++++- .../Magento/GraphQl/Catalog/ProductAttributeTypeTest.php | 2 +- .../ApplicationStateComparator/_files/state-skip-list.php | 1 + .../testsuite/Magento/Eav/Model/TypeLocatorTest.php | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultSortyByBackendType.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultSortyByBackendType.php index d020008fb3b9..25a09b6e0f3f 100644 --- a/app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultSortyByBackendType.php +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultSortyByBackendType.php @@ -20,6 +20,7 @@ use Magento\Catalog\Setup\CategorySetupFactory; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchInterface; class UpdateDefaultSortyByBackendType implements DataPatchInterface { @@ -49,7 +50,7 @@ public function __construct( /** * @inheritdoc */ - public function apply() + public function apply(): UpdateDefaultSortyByBackendType { $mediaBackendModel = \Magento\Catalog\Model\Category\Attribute\Backend\DefaultSortby::class; /** @var CategorySetup $categorySetup */ @@ -60,6 +61,8 @@ public function apply() 'backend_model', $mediaBackendModel ); + + return $this; } /** diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductAttributeTypeTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductAttributeTypeTest.php index e2ee9f779401..e1b450266988 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductAttributeTypeTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductAttributeTypeTest.php @@ -156,7 +156,7 @@ public function testComplexAttributeTypeResolver() 'catalog_product' ]; $attributeTypes = [ - 'String[]', + 'String', 'String[]', 'Int', 'CatalogInventoryDataStockItemInterface[]', diff --git a/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php b/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php index 5c9faeb22ff8..5b747893fc5b 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php +++ b/dev/tests/integration/framework/Magento/TestFramework/ApplicationStateComparator/_files/state-skip-list.php @@ -314,6 +314,7 @@ Magento\Catalog\Model\Category\Attribute\Backend\Image\Interceptor::class => null, Magento\Catalog\Model\Attribute\Backend\Startdate\Interceptor::class => null, Magento\Eav\Model\Entity\Attribute\Backend\Datetime\Interceptor::class => null, + Magento\Catalog\Model\Category\Attribute\Backend\DefaultSortby\Interceptor::class => null, Magento\Catalog\Model\Category\Attribute\Backend\Sortby\Interceptor::class => null, Magento\Catalog\Model\Category\Attribute\Backend\LayoutUpdate\Interceptor::class => null, Magento\Catalog\Model\Attribute\Backend\Customlayoutupdate\Interceptor::class => null, diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/TypeLocatorTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/TypeLocatorTest.php index 11f1fe3f7b4e..60f1d085ad28 100644 --- a/dev/tests/integration/testsuite/Magento/Eav/Model/TypeLocatorTest.php +++ b/dev/tests/integration/testsuite/Magento/Eav/Model/TypeLocatorTest.php @@ -193,7 +193,7 @@ public function getExpectedAttributeTypesProvider(): array 'custom_design_to' => 'string', 'available_sort_by' => 'string[]', 'page_layout' => 'string', - 'default_sort_by' => 'string[]', + 'default_sort_by' => 'string', 'filter_price_range' => 'double', 'custom_layout_update' => 'string', ]
escapeHtml(__('Track history')) ?>
escapeHtml(__('Location')) ?>escapeHtml(__('Date')) ?>escapeHtml(__('Local Time')) ?>escapeHtml(__('Description')) ?>escapeHtml(__('Location')) ?>escapeHtml(__('Date')) ?>escapeHtml(__('Local Time')) ?>escapeHtml(__('Description')) ?>
- escapeHtml($detail['deliverylocation']) : '') ?> + + escapeHtml($detail['deliverylocation']) : '') ?> + + - escapeHtml($detail['activity']) : '') ?> + + escapeHtml($detail['activity']) : '') ?>