From b300c94f4dc39c60c3421db4531fdeb2fe277221 Mon Sep 17 00:00:00 2001 From: Buba Suma Date: Wed, 18 Sep 2019 11:25:09 -0500 Subject: [PATCH 01/61] MC-19870: Update Regions list for China country - Add data patch for china regions --- .../Customer/Test/Mftf/Data/AddressData.xml | 15 +++ ...orefrontUpdateCustomerAddressChinaTest.xml | 51 ++++++++ .../Setup/Patch/Data/AddDataForChina.php | 117 ++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressChinaTest.xml create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForChina.php diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index 4d7a39b3246e..437eea10994d 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -239,6 +239,21 @@ Côtes-d'Armor 12345 + + Xian + Shai + Hunan Fenmian + +86 851 8410 4337 + + Nanyuan Rd, Wudang + Hunan Fenmian + + CN + China + Guiyang + Guizhou Sheng + 550002 + Jany Doe diff --git a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressChinaTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressChinaTest.xml new file mode 100644 index 000000000000..285de8d777b4 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressChinaTest.xml @@ -0,0 +1,51 @@ + + + + + + + + + <description value="Update customer address on storefront with china address and verify you can select a region"/> + <testCaseId value="MC-20234"/> + <severity value="AVERAGE"/> + <group value="customer"/> + </annotations> + + <before> + <actionGroup ref = "LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SignUpNewUserFromStorefrontActionGroup" stepKey="SignUpNewUser"> + <argument name="Customer" value="CustomerEntityOne"/> + </actionGroup> + </before> + <after> + <actionGroup ref="DeleteCustomerByEmailActionGroup" stepKey="deleteNewUser"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Update customer address in storefront--> + <actionGroup ref="EnterCustomerAddressInfo" stepKey="enterAddress"> + <argument name="Address" value="updateCustomerChinaAddress"/> + </actionGroup> + <!--Verify customer address save success message--> + <see selector="{{AdminCustomerMessagesSection.successMessage}}" userInput="You saved the address." stepKey="seeAssertCustomerAddressSuccessSaveMessage"/> + + <!--Verify customer default billing address--> + <actionGroup ref="VerifyCustomerBillingAddressWithState" stepKey="verifyBillingAddress"> + <argument name="address" value="updateCustomerChinaAddress"/> + </actionGroup> + + <!--Verify customer default shipping address--> + <actionGroup ref="VerifyCustomerShippingAddressWithState" stepKey="verifyShippingAddress"> + <argument name="address" value="updateCustomerChinaAddress"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForChina.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForChina.php new file mode 100644 index 000000000000..0750f8056c4d --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForChina.php @@ -0,0 +1,117 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Directory\Setup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add China States + */ +class AddDataForChina implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var \Magento\Directory\Setup\DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * @param ModuleDataSetupInterface $moduleDataSetup + * @param \Magento\Directory\Setup\DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + \Magento\Directory\Setup\DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForChina() + ); + } + + /** + * China states data. + * + * @return array + */ + private function getDataForChina() + { + return [ + ['CN', 'CN-AH', 'Anhui Sheng'], + ['CN', 'CN-BJ', 'Beijing Shi'], + ['CN', 'CN-CQ', 'Chongqing Shi'], + ['CN', 'CN-FJ', 'Fujian Sheng'], + ['CN', 'CN-GS', 'Gansu Sheng'], + ['CN', 'CN-GD', 'Guangdong Sheng'], + ['CN', 'CN-GX', 'Guangxi Zhuangzu Zizhiqu'], + ['CN', 'CN-GZ', 'Guizhou Sheng'], + ['CN', 'CN-HI', 'Hainan Sheng'], + ['CN', 'CN-HE', 'Hebei Sheng'], + ['CN', 'CN-HL', 'Heilongjiang Sheng'], + ['CN', 'CN-HA', 'Henan Sheng'], + ['CN', 'CN-HK', 'Hong Kong SAR'], + ['CN', 'CN-HB', 'Hubei Sheng'], + ['CN', 'CN-HN', 'Hunan Sheng'], + ['CN', 'CN-JS', 'Jiangsu Sheng'], + ['CN', 'CN-JX', 'Jiangxi Sheng'], + ['CN', 'CN-JL', 'Jilin Sheng'], + ['CN', 'CN-LN', 'Liaoning Sheng'], + ['CN', 'CN-MO', 'Macao SAR'], + ['CN', 'CN-NM', 'Nei Mongol Zizhiqu'], + ['CN', 'CN-NX', 'Ningxia Huizi Zizhiqu'], + ['CN', 'CN-QH', 'Qinghai Sheng'], + ['CN', 'CN-SN', 'Shaanxi Sheng'], + ['CN', 'CN-SD', 'Shandong Sheng'], + ['CN', 'CN-SH', 'Shanghai Shi'], + ['CN', 'CN-SX', 'Shanxi Sheng'], + ['CN', 'CN-SC', 'Sichuan Sheng'], + ['CN', 'CN-TW', 'Taiwan Sheng'], + ['CN', 'CN-TJ', 'Tianjin Shi'], + ['CN', 'CN-XJ', 'Xinjiang Uygur Zizhiqu'], + ['CN', 'CN-XZ', 'Xizang Zizhiqu'], + ['CN', 'CN-YN', 'Yunnan Sheng'], + ['CN', 'CN-ZJ', 'Zhejiang Sheng'], + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} From 6a648202b3bf6d93f357901f31f51292982fe1d7 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Fri, 20 Sep 2019 10:40:57 -0500 Subject: [PATCH 02/61] MC-17518: Cart Rest API not showing all shipping assignments for multi-shipping --- .../Controller/Checkout/Plugin.php | 22 ++- .../MultishippingQuoteRepositoryPlugin.php | 159 ++++++++++++++++++ .../Plugin/ResetShippingAssigmentPlugin.php | 52 ++++++ .../Unit/Controller/Checkout/PluginTest.php | 63 +++++-- app/code/Magento/Multishipping/etc/di.xml | 3 + .../Magento/Multishipping/etc/frontend/di.xml | 3 + .../Magento/Quote/Api/CartRepositoryTest.php | 79 ++++++++- 7 files changed, 354 insertions(+), 27 deletions(-) create mode 100644 app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepositoryPlugin.php create mode 100644 app/code/Magento/Multishipping/Plugin/ResetShippingAssigmentPlugin.php diff --git a/app/code/Magento/Multishipping/Controller/Checkout/Plugin.php b/app/code/Magento/Multishipping/Controller/Checkout/Plugin.php index f88cdfc26fa9..f60feb2b834b 100644 --- a/app/code/Magento/Multishipping/Controller/Checkout/Plugin.php +++ b/app/code/Magento/Multishipping/Controller/Checkout/Plugin.php @@ -7,36 +7,44 @@ namespace Magento\Multishipping\Controller\Checkout; +use Magento\Checkout\Model\Cart; +use Magento\Framework\App\Action\Action; + /** * Turns Off Multishipping mode for Quote. */ class Plugin { /** - * @var \Magento\Checkout\Model\Cart + * @var Cart */ - protected $cart; + private $cart; /** - * @param \Magento\Checkout\Model\Cart $cart + * @param Cart $cart */ - public function __construct(\Magento\Checkout\Model\Cart $cart) - { + public function __construct( + Cart $cart + ) { $this->cart = $cart; } /** * Disable multishipping * - * @param \Magento\Framework\App\Action\Action $subject + * @param Action $subject * @return void * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function beforeExecute(\Magento\Framework\App\Action\Action $subject) + public function beforeExecute(Action $subject) { $quote = $this->cart->getQuote(); if ($quote->getIsMultiShipping()) { $quote->setIsMultiShipping(0); + $extensionAttributes = $quote->getExtensionAttributes(); + if ($extensionAttributes && $extensionAttributes->getShippingAssignments()) { + $extensionAttributes->setShippingAssignments([]); + } $this->cart->saveQuote(); } } diff --git a/app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepositoryPlugin.php b/app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepositoryPlugin.php new file mode 100644 index 000000000000..db972cf9bd7c --- /dev/null +++ b/app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepositoryPlugin.php @@ -0,0 +1,159 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Multishipping\Plugin; + +use Magento\Framework\Api\SearchResultsInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\ShippingAssignment\ShippingProcessor; +use Magento\Quote\Model\ShippingAssignmentFactory; + +/** + * Plugin for multishipping quote processing in WebAPI. + */ +class MultishippingQuoteRepositoryPlugin +{ + /** + * @var ShippingAssignmentFactory + */ + private $shippingAssignmentFactory; + + /** + * @var ShippingProcessor + */ + private $shippingProcessor; + + /** + * @param ShippingAssignmentFactory $shippingAssignmentFactory + * @param ShippingProcessor $shippingProcessor + */ + public function __construct( + ShippingAssignmentFactory $shippingAssignmentFactory, + ShippingProcessor $shippingProcessor + ) { + $this->shippingAssignmentFactory = $shippingAssignmentFactory; + $this->shippingProcessor = $shippingProcessor; + } + + /** + * Process multishipping quote for get. + * + * @param CartRepositoryInterface $subject + * @param CartInterface $result + * @return CartInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGet( + CartRepositoryInterface $subject, + CartInterface $result + ) { + return $this->processQuote($result); + } + + /** + * Process multishipping quote for get list. + * + * @param CartRepositoryInterface $subject + * @param SearchResultsInterface $result + * + * @return SearchResultsInterface + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetList( + CartRepositoryInterface $subject, + SearchResultsInterface $result + ) { + $items = []; + foreach ($result->getItems() as $item) { + $items[] = $this->processQuote($item); + } + $result->setItems($items); + + return $result; + } + + /** + * Remove shipping assignments for multishipping quote. + * + * @param CartRepositoryInterface $subject + * @param CartInterface $quote + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeSave(CartRepositoryInterface $subject, CartInterface $quote) + { + $extensionAttributes = $quote->getExtensionAttributes(); + if ($quote->getIsMultiShipping() && $extensionAttributes && $extensionAttributes->getShippingAssignments()) { + $quote->getExtensionAttributes()->setShippingAssignments([]); + } + + return [$quote]; + } + + /** + * Set shipping assignments for multishipping quote according to customer selection. + * + * @param CartInterface $quote + * @return CartInterface + */ + private function processQuote(CartInterface $quote): CartInterface + { + if (!$quote->getIsMultiShipping() || !$quote instanceof Quote) { + return $quote; + } + + if ($quote->getExtensionAttributes() && $quote->getExtensionAttributes()->getShippingAssignments()) { + $shippingAssignments = []; + $addresses = $quote->getAllAddresses(); + + foreach ($addresses as $address) { + $quoteItems = $this->getQuoteItems($quote, $address); + if (!empty($quoteItems)) { + $shippingAssignment = $this->shippingAssignmentFactory->create(); + $shippingAssignment->setItems($quoteItems); + $shippingAssignment->setShipping($this->shippingProcessor->create($address)); + $shippingAssignments[] = $shippingAssignment; + } + } + + if (!empty($shippingAssignments)) { + $quote->getExtensionAttributes()->setShippingAssignments($shippingAssignments); + } + } + + return $quote; + } + + /** + * Returns quote items assigned to address. + * + * @param Quote $quote + * @param Quote\Address $address + * @return Quote\Item[] + */ + private function getQuoteItems(Quote $quote, Quote\Address $address): array + { + $quoteItems = []; + foreach ($address->getItemsCollection() as $addressItem) { + $quoteItem = $quote->getItemById($addressItem->getQuoteItemId()); + if ($quoteItem) { + $multishippingQuoteItem = clone $quoteItem; + $qty = $addressItem->getQty(); + $sku = $multishippingQuoteItem->getSku(); + if (isset($quoteItems[$sku])) { + $qty += $quoteItems[$sku]->getQty(); + } + $multishippingQuoteItem->setQty($qty); + $quoteItems[$sku] = $multishippingQuoteItem; + } + } + + return array_values($quoteItems); + } +} diff --git a/app/code/Magento/Multishipping/Plugin/ResetShippingAssigmentPlugin.php b/app/code/Magento/Multishipping/Plugin/ResetShippingAssigmentPlugin.php new file mode 100644 index 000000000000..376dbf723b88 --- /dev/null +++ b/app/code/Magento/Multishipping/Plugin/ResetShippingAssigmentPlugin.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Multishipping\Plugin; + +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\ShippingAssignment\ShippingAssignmentProcessor; + +/** + * Resets quote shipping assignments when item is removed from multishipping quote. + */ +class ResetShippingAssigmentPlugin +{ + /** + * @var ShippingAssignmentProcessor + */ + private $shippingAssignmentProcessor; + + /** + * @param ShippingAssignmentProcessor $shippingAssignmentProcessor + */ + public function __construct( + ShippingAssignmentProcessor $shippingAssignmentProcessor + ) { + $this->shippingAssignmentProcessor = $shippingAssignmentProcessor; + } + + /** + * Resets quote shipping assignments when item is removed from multishipping quote. + * + * @param Quote $subject + * @param mixed $itemId + * + * @return array + */ + public function beforeRemoveItem(Quote $subject, $itemId): array + { + if ($subject->getIsMultiShipping()) { + $extensionAttributes = $subject->getExtensionAttributes(); + if ($extensionAttributes && $extensionAttributes->getShippingAssignments()) { + $shippingAssignment = $this->shippingAssignmentProcessor->create($subject); + $extensionAttributes->setShippingAssignments([$shippingAssignment]); + } + } + + return [$itemId]; + } +} diff --git a/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php b/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php index a26f2661ebab..bbcd6d85c501 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php @@ -4,53 +4,90 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - declare(strict_types=1); namespace Magento\Multishipping\Test\Unit\Controller\Checkout; +use Magento\Checkout\Controller\Index\Index; +use Magento\Checkout\Model\Cart; use Magento\Multishipping\Controller\Checkout\Plugin; +use Magento\Quote\Api\Data\CartExtensionInterface; +use Magento\Quote\Api\Data\ShippingAssignmentInterface; +use Magento\Quote\Model\Quote; +/** + * Class PluginTest + */ class PluginTest extends \PHPUnit\Framework\TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $cartMock; + private $cartMock; /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $quoteMock; + private $quoteMock; /** * @var Plugin */ - protected $object; + private $object; + /** + * @inheritdoc + */ protected function setUp() { - $this->cartMock = $this->createMock(\Magento\Checkout\Model\Cart::class); + $this->cartMock = $this->createMock(Cart::class); $this->quoteMock = $this->createPartialMock( - \Magento\Quote\Model\Quote::class, - ['__wakeUp', 'setIsMultiShipping', 'getIsMultiShipping'] + Quote::class, + ['__wakeUp', 'setIsMultiShipping', 'getIsMultiShipping', 'getExtensionAttributes'] ); - $this->cartMock->expects($this->once())->method('getQuote')->will($this->returnValue($this->quoteMock)); + $this->cartMock->expects($this->once()) + ->method('getQuote') + ->will($this->returnValue($this->quoteMock)); $this->object = new \Magento\Multishipping\Controller\Checkout\Plugin($this->cartMock); } + /** + * Tests turn off multishipping on multishipping quote. + * + * @return void + */ public function testExecuteTurnsOffMultishippingModeOnMultishippingQuote(): void { - $subject = $this->createMock(\Magento\Checkout\Controller\Index\Index::class); - $this->quoteMock->expects($this->once())->method('getIsMultiShipping')->willReturn(1); - $this->quoteMock->expects($this->once())->method('setIsMultiShipping')->with(0); - $this->cartMock->expects($this->once())->method('saveQuote'); + $subject = $this->createMock(Index::class); + $extensionAttributes = $this->createMock(CartExtensionInterface::class); + $extensionAttributes->method('getShippingAssignments') + ->willReturn( + $this->createMock(ShippingAssignmentInterface::class) + ); + $extensionAttributes->expects($this->once()) + ->method('setShippingAssignments') + ->with([]); + $this->quoteMock->method('getExtensionAttributes') + ->willReturn($extensionAttributes); + $this->quoteMock->expects($this->once()) + ->method('getIsMultiShipping')->willReturn(1); + $this->quoteMock->expects($this->once()) + ->method('setIsMultiShipping') + ->with(0); + $this->cartMock->expects($this->once()) + ->method('saveQuote'); + $this->object->beforeExecute($subject); } + /** + * Tests turn off multishipping on non-multishipping quote. + * + * @return void + */ public function testExecuteTurnsOffMultishippingModeOnNotMultishippingQuote(): void { - $subject = $this->createMock(\Magento\Checkout\Controller\Index\Index::class); + $subject = $this->createMock(Index::class); $this->quoteMock->expects($this->once())->method('getIsMultiShipping')->willReturn(0); $this->quoteMock->expects($this->never())->method('setIsMultiShipping'); $this->cartMock->expects($this->never())->method('saveQuote'); diff --git a/app/code/Magento/Multishipping/etc/di.xml b/app/code/Magento/Multishipping/etc/di.xml index 3bccf0b74bcd..993376da8378 100644 --- a/app/code/Magento/Multishipping/etc/di.xml +++ b/app/code/Magento/Multishipping/etc/di.xml @@ -9,4 +9,7 @@ <type name="Magento\Quote\Model\Cart\CartTotalRepository"> <plugin name="multishipping_shipping_addresses" type="Magento\Multishipping\Model\Cart\CartTotalRepositoryPlugin" /> </type> + <type name="Magento\Quote\Model\QuoteRepository"> + <plugin name="multishipping_quote_repository" type="Magento\Multishipping\Plugin\MultishippingQuoteRepositoryPlugin" /> + </type> </config> diff --git a/app/code/Magento/Multishipping/etc/frontend/di.xml b/app/code/Magento/Multishipping/etc/frontend/di.xml index 0c2daaf45043..3d85f4c8a447 100644 --- a/app/code/Magento/Multishipping/etc/frontend/di.xml +++ b/app/code/Magento/Multishipping/etc/frontend/di.xml @@ -45,4 +45,7 @@ <type name="Magento\Checkout\Controller\Cart"> <plugin name="multishipping_clear_addresses" type="Magento\Multishipping\Model\Cart\Controller\CartPlugin" sortOrder="50" /> </type> + <type name="Magento\Quote\Model\Quote"> + <plugin name="multishipping_reset_shipping_assigment" type="Magento\Multishipping\Plugin\ResetShippingAssigmentPlugin"/> + </type> </config> diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php index 8cb82f5c8f20..7ffc4311e40e 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php @@ -42,6 +42,9 @@ class CartRepositoryTest extends WebapiAbstract */ private $filterBuilder; + /** + * @inheritdoc + */ protected function setUp() { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -59,8 +62,12 @@ protected function setUp() protected function tearDown() { try { + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class); $cart = $this->getCart('test01'); - $cart->delete(); + $quoteRepository->delete($cart); + $cart = $this->getCart('multishipping_quote_id'); + $quoteRepository->delete($cart); } catch (\InvalidArgumentException $e) { // Do nothing if cart fixture was not used } @@ -74,18 +81,27 @@ protected function tearDown() * @return \Magento\Quote\Model\Quote * @throws \InvalidArgumentException */ - protected function getCart($reservedOrderId) + private function getCart($reservedOrderId) { - /** @var $cart \Magento\Quote\Model\Quote */ - $cart = $this->objectManager->get(\Magento\Quote\Model\Quote::class); - $cart->load($reservedOrderId, 'reserved_order_id'); - if (!$cart->getId()) { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class); + $items = $quoteRepository->getList($searchCriteria)->getItems(); + + if (empty($items)) { throw new \InvalidArgumentException('There is no quote with provided reserved order ID.'); } - return $cart; + + return array_pop($items); } /** + * Tests successfull get cart web-api call. + * * @magentoApiDataFixture Magento/Sales/_files/quote.php */ public function testGetCart() @@ -130,6 +146,52 @@ public function testGetCart() } /** + * Tests that multishipping quote contains all addresses in shipping assignments. + * + * @magentoApiDataFixture Magento/Multishipping/Fixtures/quote_with_split_items.php + */ + public function testGetMultishippingCart() + { + $cart = $this->getCart('multishipping_quote_id'); + $cartId = $cart->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'quoteCartRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'quoteCartRepositoryV1Get', + ], + ]; + + $requestData = ['cartId' => $cartId]; + $cartData = $this->_webApiCall($serviceInfo, $requestData); + + $shippingAssignments = $cart->getExtensionAttributes()->getShippingAssignments(); + foreach ($shippingAssignments as $key => $shippingAssignment) { + $address = $shippingAssignment->getShipping()->getAddress(); + $cartItem = $shippingAssignment->getItems()[0]; + $this->assertEquals( + $address->getId(), + $cartData['extension_attributes']['shipping_assignments'][$key]['shipping']['address']['id'] + ); + $this->assertEquals( + $cartItem->getSku(), + $cartData['extension_attributes']['shipping_assignments'][$key]['items'][0]['sku'] + ); + $this->assertEquals( + $cartItem->getQty(), + $cartData['extension_attributes']['shipping_assignments'][$key]['items'][0]['qty'] + ); + } + } + + /** + * Tests exception when cartId is not provided. + * * @expectedException \Exception * @expectedExceptionMessage No such entity with */ @@ -154,6 +216,8 @@ public function testGetCartThrowsExceptionIfThereIsNoCartWithProvidedId() } /** + * Tests carts search. + * * @magentoApiDataFixture Magento/Sales/_files/quote.php */ public function testGetList() @@ -184,6 +248,7 @@ public function testGetList() $this->searchCriteriaBuilder->addFilters([$grandTotalFilter, $subtotalFilter]); $this->searchCriteriaBuilder->addFilters([$minCreatedAtFilter]); $this->searchCriteriaBuilder->addFilters([$maxCreatedAtFilter]); + $this->searchCriteriaBuilder->addFilter('reserved_order_id', 'test01'); /** @var SortOrder $sortOrder */ $sortOrder = $this->sortOrderBuilder->setField('subtotal')->setDirection(SortOrder::SORT_ASC)->create(); $this->searchCriteriaBuilder->setSortOrders([$sortOrder]); From 2d86f3971dab3ddce51a65060417a378f4904ef6 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Mon, 23 Sep 2019 11:45:19 -0500 Subject: [PATCH 03/61] MC-17518: Cart Rest API not showing all shipping assignments for multi-shipping --- .../Test/Unit/Controller/Checkout/PluginTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php b/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php index bbcd6d85c501..5397317ca299 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php @@ -59,7 +59,10 @@ protected function setUp() public function testExecuteTurnsOffMultishippingModeOnMultishippingQuote(): void { $subject = $this->createMock(Index::class); - $extensionAttributes = $this->createMock(CartExtensionInterface::class); + $extensionAttributes = $this->createPartialMock( + CartExtensionInterface::class, + ['setShippingAssignments', 'getShippingAssignments'] + ); $extensionAttributes->method('getShippingAssignments') ->willReturn( $this->createMock(ShippingAssignmentInterface::class) From 7774abcb8ffb50937ad568893c073d997164b62d Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Tue, 24 Sep 2019 14:08:29 -0500 Subject: [PATCH 04/61] MC-20346: Update Regions list for Belgium country --- .../Customer/Test/Mftf/Data/AddressData.xml | 15 +++ ...efrontUpdateCustomerAddressBelgiumTest.xml | 51 ++++++++++ .../Setup/Patch/Data/AddDataForBelgium.php | 94 +++++++++++++++++++ 3 files changed, 160 insertions(+) create mode 100644 app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressBelgiumTest.xml create mode 100644 app/code/Magento/Directory/Setup/Patch/Data/AddDataForBelgium.php diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index 4d7a39b3246e..f1d1a1d683db 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -312,4 +312,19 @@ <data key="postcode">90230</data> <data key="telephone">555-55-555-55</data> </entity> + <entity name="updateCustomerBelgiumAddress" type="address"> + <data key="firstname">John</data> + <data key="lastname">Doe</data> + <data key="company">Magento</data> + <array key="street"> + <item>Chaussee de Wavre</item> + <item>318</item> + </array> + <data key="city">Bihain</data> + <data key="state">Hainaut</data> + <data key="country_id">BE</data> + <data key="country">Belgium</data> + <data key="postcode">6690</data> + <data key="telephone">0477-58-77867</data> + </entity> </entities> diff --git a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressBelgiumTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressBelgiumTest.xml new file mode 100644 index 000000000000..6c0615f701df --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontUpdateCustomerAddressBelgiumTest.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="StorefrontUpdateCustomerAddressBelgiumTest"> + <annotations> + <stories value="Update Regions list for Belgium country"/> + <title value="Update customer address on storefront with Belgium address"/> + <description value="Update customer address on storefront with Belgium address and verify you can select a region"/> + <testCaseId value="MC-20234"/> + <severity value="AVERAGE"/> + <group value="customer"/> + </annotations> + + <before> + <actionGroup ref = "LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SignUpNewUserFromStorefrontActionGroup" stepKey="SignUpNewUser"> + <argument name="Customer" value="CustomerEntityOne"/> + </actionGroup> + </before> + <after> + <actionGroup ref="DeleteCustomerByEmailActionGroup" stepKey="deleteNewUser"> + <argument name="email" value="{{CustomerEntityOne.email}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Update customer address Belgium in storefront--> + <actionGroup ref="EnterCustomerAddressInfo" stepKey="enterAddress"> + <argument name="Address" value="updateCustomerBelgiumAddress"/> + </actionGroup> + <!--Verify customer address save success message--> + <see selector="{{AdminCustomerMessagesSection.successMessage}}" userInput="You saved the address." stepKey="seeAssertCustomerAddressSuccessSaveMessage"/> + + <!--Verify customer default billing address--> + <actionGroup ref="VerifyCustomerBillingAddressWithState" stepKey="verifyBillingAddress"> + <argument name="address" value="updateCustomerBelgiumAddress"/> + </actionGroup> + + <!--Verify customer default shipping address--> + <actionGroup ref="VerifyCustomerShippingAddressWithState" stepKey="verifyShippingAddress"> + <argument name="address" value="updateCustomerBelgiumAddress"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForBelgium.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForBelgium.php new file mode 100644 index 000000000000..7e53198cb9a4 --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForBelgium.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Directory\Setup\Patch\Data; + +use Magento\Directory\Setup\DataInstaller; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; + +/** + * Add Regions for Belgium. + */ +class AddDataForBelgium implements DataPatchInterface +{ + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var \Magento\Directory\Setup\DataInstallerFactory + */ + private $dataInstallerFactory; + + /** + * @param ModuleDataSetupInterface $moduleDataSetup + * @param \Magento\Directory\Setup\DataInstallerFactory $dataInstallerFactory + */ + public function __construct( + ModuleDataSetupInterface $moduleDataSetup, + \Magento\Directory\Setup\DataInstallerFactory $dataInstallerFactory + ) { + $this->moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * @inheritdoc + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForBelgium() + ); + } + + /** + * Belgium states data. + * + * @return array + */ + private function getDataForBelgium() + { + return [ + ['BE', 'VAN', 'Antwerpen'], + ['BE', 'WBR', 'Brabant wallon'], + ['BE', 'BRU', 'Brussels Hoofdstedelijk Gewest'], + ['BE', 'WHT', 'Hainaut'], + ['BE', 'VLI', 'Limburg'], + ['BE', 'WLG', 'Liege'], + ['BE', 'WLX', 'Luxembourg'], + ['BE', 'WNA', 'Namur'], + ['BE', 'VOV', 'Oost-Vlaanderen'], + ['BE', 'VLG', 'Vlaams Gewest'], + ['BE', 'VBR', 'Vlaams-Brabant'], + ['BE', 'VWV', 'West-Vlaanderen'], + ['BE', 'WAL', 'Wallonne, Region'] + ]; + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} From 28d119cdb20899c7881ed06b8d3ab99dd8a78b63 Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Wed, 25 Sep 2019 16:18:57 -0500 Subject: [PATCH 05/61] MC-15986: Category Filtering - added Schema changes --- app/code/Magento/CatalogGraphQl/etc/schema.graphqls | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 140aab37c9ce..24a2123ff60f 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -11,7 +11,8 @@ type Query { ): Products @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Products") @doc(description: "The products query searches for products that match the criteria specified in the search and filter attributes.") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\Identity") category ( - id: Int @doc(description: "Id of the category.") + id: Int @doc(description: "Id of the category.") + filter: CategoryFilterInput @doc(description: "Identifies which Category inputs to search for and return."), ): CategoryTree @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") @doc(description: "The category query searches for categories that match the criteria specified in the search and filter attributes.") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryTreeIdentity") } @@ -277,6 +278,12 @@ input ProductAttributeFilterInput @doc(description: "ProductAttributeFilterInput category_id: FilterEqualTypeInput @doc(description: "Filter product by category id") } +input CategoryFilterInput @doc(description: "CategoryFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { + id: FilterEqualTypeInput @doc(description: "Filter by category ID that uniquely identifies and filters the category."), + url_key: FilterEqualTypeInput @doc(description: "Filter by the part of the URL that identifies the category"), + name: FilterEqualTypeInput @doc(description: "Filter by the display name of the category.") +} + input ProductFilterInput @doc(description: "ProductFilterInput is deprecated, use @ProductAttributeFilterInput instead. ProductFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { name: FilterTypeInput @doc(description: "The product name. Customers use this name to identify the product.") sku: FilterTypeInput @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer.") From c15e194a9c5395d6cc703813feea8ed6efc4f6d5 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Mon, 30 Sep 2019 15:28:18 -0500 Subject: [PATCH 06/61] MAGETWO-99043: Shipping Methods Don't Load In IE11 --- .../frontend/web/js/model/address-converter.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js index 9b20a782c38d..c114b795a80b 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/address-converter.js @@ -9,8 +9,9 @@ define([ 'jquery', 'Magento_Checkout/js/model/new-customer-address', 'Magento_Customer/js/customer-data', - 'mage/utils/objects' -], function ($, address, customerData, mageUtils) { + 'mage/utils/objects', + 'underscore' +], function ($, address, customerData, mageUtils, _) { 'use strict'; var countryData = customerData.get('directory-data'); @@ -59,13 +60,15 @@ define([ delete addressData['region_id']; if (addressData['custom_attributes']) { - addressData['custom_attributes'] = Object.entries(addressData['custom_attributes']) - .map(function (customAttribute) { + addressData['custom_attributes'] = _.map( + addressData['custom_attributes'], + function (value, key) { return { - 'attribute_code': customAttribute[0], - 'value': customAttribute[1] + 'attribute_code': key, + 'value': value }; - }); + } + ); } return address(addressData); From 2c926f032a4f1197b9aa6f52d4abeddc6e511e97 Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Tue, 1 Oct 2019 11:57:22 -0500 Subject: [PATCH 07/61] MC-15986: Category Filtering - added new schema changes from approved proposal --- .../Magento/CatalogGraphQl/etc/schema.graphqls | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 24a2123ff60f..66e6fb68728f 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -12,9 +12,11 @@ type Query { @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\Products") @doc(description: "The products query searches for products that match the criteria specified in the search and filter attributes.") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Product\\Identity") category ( id: Int @doc(description: "Id of the category.") - filter: CategoryFilterInput @doc(description: "Identifies which Category inputs to search for and return."), ): CategoryTree - @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") @doc(description: "The category query searches for categories that match the criteria specified in the search and filter attributes.") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryTreeIdentity") + @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") @doc(description: "The category query searches for categories that match the criteria specified in the search and filter attributes.") @deprecated(reason: "Use 'categoryList' query instead of 'category' query") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryTreeIdentity") + categoryList( + filters: CategoryFilterInput @doc(description: "Identifies which Category filter inputs to search for and return.") + ): [CategoryList] @doc(description: "Categories filter.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") } type Price @doc(description: "The Price object defines the price of a product as well as any tax-related adjustments.") { @@ -278,10 +280,11 @@ input ProductAttributeFilterInput @doc(description: "ProductAttributeFilterInput category_id: FilterEqualTypeInput @doc(description: "Filter product by category id") } -input CategoryFilterInput @doc(description: "CategoryFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { - id: FilterEqualTypeInput @doc(description: "Filter by category ID that uniquely identifies and filters the category."), - url_key: FilterEqualTypeInput @doc(description: "Filter by the part of the URL that identifies the category"), - name: FilterEqualTypeInput @doc(description: "Filter by the display name of the category.") +input CategoryFilterInput @doc(description: "CategoryFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") +{ + ids: FilterEqualTypeInput @doc(description: "Filter by category ID that uniquely identifies and filters the category.") + url_key: FilterEqualTypeInput @doc(description: "Filter by the part of the URL that identifies the category") + name: FilterMatchTypeInput @doc(description: "Filter by the display name of the category.") } input ProductFilterInput @doc(description: "ProductFilterInput is deprecated, use @ProductAttributeFilterInput instead. ProductFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { From 854a9d6d8b3e46aee985901d2acf4300fa513c42 Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Tue, 1 Oct 2019 15:05:21 -0500 Subject: [PATCH 08/61] MC-15986: Category Filtering - added change to the query in schema --- app/code/Magento/CatalogGraphQl/etc/schema.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 66e6fb68728f..5e8f5590bbd3 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -16,7 +16,7 @@ type Query { @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") @doc(description: "The category query searches for categories that match the criteria specified in the search and filter attributes.") @deprecated(reason: "Use 'categoryList' query instead of 'category' query") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryTreeIdentity") categoryList( filters: CategoryFilterInput @doc(description: "Identifies which Category filter inputs to search for and return.") - ): [CategoryList] @doc(description: "Categories filter.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") + ): [CategoryTree] @doc(description: "Categories filter.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") } type Price @doc(description: "The Price object defines the price of a product as well as any tax-related adjustments.") { From 179c5a2f3a3748beeec43807738674438f793b85 Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Thu, 3 Oct 2019 06:26:10 -0500 Subject: [PATCH 09/61] MC-15986: Category Filtering - added description changes from review --- app/code/Magento/CatalogGraphQl/etc/schema.graphqls | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 5e8f5590bbd3..5712db9f8bc7 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -16,7 +16,7 @@ type Query { @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") @doc(description: "The category query searches for categories that match the criteria specified in the search and filter attributes.") @deprecated(reason: "Use 'categoryList' query instead of 'category' query") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryTreeIdentity") categoryList( filters: CategoryFilterInput @doc(description: "Identifies which Category filter inputs to search for and return.") - ): [CategoryTree] @doc(description: "Categories filter.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") + ): [CategoryTree] @doc(description: "Returns an array of categories based on the specified filters.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") } type Price @doc(description: "The Price object defines the price of a product as well as any tax-related adjustments.") { @@ -113,7 +113,7 @@ type CustomizableAreaValue @doc(description: "CustomizableAreaValue defines the max_characters: Int @doc(description: "The maximum number of characters that can be entered for this customizable option.") } -type CategoryTree implements CategoryInterface @doc(description: "Category Tree implementation.") { +type CategoryTree implements CategoryInterface @doc(description: "An array containing the filtered categories and their subcategories") { children: [CategoryTree] @doc(description: "Child categories tree.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") } @@ -282,7 +282,7 @@ input ProductAttributeFilterInput @doc(description: "ProductAttributeFilterInput input CategoryFilterInput @doc(description: "CategoryFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") { - ids: FilterEqualTypeInput @doc(description: "Filter by category ID that uniquely identifies and filters the category.") + ids: FilterEqualTypeInput @doc(description: "Filter by category ID that uniquely identifies the category.") url_key: FilterEqualTypeInput @doc(description: "Filter by the part of the URL that identifies the category") name: FilterMatchTypeInput @doc(description: "Filter by the display name of the category.") } From fa4567a98747918f0e8554443897b55584c16e1f Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Thu, 3 Oct 2019 06:35:24 -0500 Subject: [PATCH 10/61] MC-15986: Category Filtering - added resolver for category tree --- .../Model/Category/CategoryFilter.php | 66 +++++++++++ .../Model/Resolver/CategoryList.php | 105 ++++++++++++++++++ .../Products/Query/FieldSelection.php | 6 +- 3 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php new file mode 100644 index 000000000000..574f5dd2715c --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php @@ -0,0 +1,66 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Category;; + +use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; +use Magento\Catalog\Api\CategoryRepositoryInterface; + +/** + * Category filter allows to filter collection using 'id, url_key, name' from search criteria. + */ +class CategoryFilter +{ + /** + * @var CollectionFactory + */ + private $collectionFactory; + + /** + * @var CategoryRepositoryInterface + */ + private $categoryRepository; + + /** + * @param CategoryRepositoryInterface $categoryRepository; + * @param CollectionFactory $collectionFactory + */ + public function __construct( + CategoryRepositoryInterface $categoryRepository, + CollectionFactory $collectionFactory + ) { + $this->categoryRepository = $categoryRepository; + $this->collectionFactory = $collectionFactory; + } + + /** + * Filter for filtering the requested categories id's based on url_key, ids, name in the result. + * + * @param array $args + * + * @return array|int + */ + public function applyFilters(array $args) + { + $categoryCollection = $this->collectionFactory->create(); + foreach($args['filters'] as $field => $cond){ + foreach($cond as $condType => $value){ + if($field === 'ids'){ + $categoryCollection->addIdFilter($value); + } else { + $categoryCollection->addAttributeToFilter($field, [$condType => $value]); + } + } + } + $categoryIds = []; + $categoriesData = $categoryCollection->getData(); + foreach ($categoriesData as $categoryData){ + $categoryIds[] = (int)$categoryData['entity_id']; + } + return $categoryIds; + } +} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php new file mode 100644 index 000000000000..932b88c68f1f --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver; + +use Magento\Catalog\Model\Category; +use Magento\CatalogGraphQl\Model\Resolver\Category\CheckCategoryIsActive; +use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ExtractDataFromCategoryTree; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; +use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\CategoryTree; +use Magento\CatalogGraphQl\Model\Category\CategoryFilter; + +/** + * Category tree resolver, used for GraphQL category data request processing. + */ +class CategoryList implements ResolverInterface +{ + /** + * Name of type in GraphQL + */ + const CATEGORY_INTERFACE = 'CategoryInterface'; + + /** + * @var CategoryTree + */ + private $categoryTree; + + /** + * @var CategoryFilter + */ + private $categoryFilter; + + /** + * @var ExtractDataFromCategoryTree + */ + private $extractDataFromCategoryTree; + + /** + * @var CheckCategoryIsActive + */ + private $checkCategoryIsActive; + + /** + * @param CategoryTree $categoryTree + * @param ExtractDataFromCategoryTree $extractDataFromCategoryTree + * @param CheckCategoryIsActive $checkCategoryIsActive + * @param CategoryFilter $categoryFilter + */ + public function __construct( + CategoryTree $categoryTree, + ExtractDataFromCategoryTree $extractDataFromCategoryTree, + CheckCategoryIsActive $checkCategoryIsActive, + CategoryFilter $categoryFilter + ) { + $this->categoryTree = $categoryTree; + $this->extractDataFromCategoryTree = $extractDataFromCategoryTree; + $this->checkCategoryIsActive = $checkCategoryIsActive; + $this->categoryFilter = $categoryFilter; + } + + /** + * @inheritdoc + */ + public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) + { + if (isset($value[$field->getName()])) { + return $value[$field->getName()]; + } + + if (!isset($args['filters'])) { + throw new GraphQlInputException( + __( "'filters' input argument is required.") + ); + } + + $rootCategoryIds = $this->categoryFilter->applyFilters($args); + $result = []; + $categoriesTreeData = []; + + foreach ($rootCategoryIds as $rootCategoryId) { + if ($rootCategoryId !== Category::TREE_ROOT_ID) { + $this->checkCategoryIsActive->execute($rootCategoryId); + } + $categoriesTree = $this->categoryTree->getTree($info, $rootCategoryId); + + if (empty($categoriesTree) || ($categoriesTree->count() == 0)) { + throw new GraphQlNoSuchEntityException(__('Category doesn\'t exist')); + } + $categoriesTreeData[] = $categoriesTree; + } + + foreach ($categoriesTreeData as $treeData ) { + $result[] = $this->extractDataFromCategoryTree->execute($treeData); + } + return current($result); + } +} diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Query/FieldSelection.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Query/FieldSelection.php index 3912bab05ebb..ae4f2e911a5b 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Query/FieldSelection.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Query/FieldSelection.php @@ -60,9 +60,9 @@ private function getProductFields(ResolveInfo $info): array $fieldNames[] = $this->collectProductFieldNames($selection, $fieldNames); } } - - $fieldNames = array_merge(...$fieldNames); - + if (!empty($fieldNames)) { + $fieldNames = array_merge(...$fieldNames); + } return $fieldNames; } From 46e21b2a4a6b3ed7aea2d4d1f4e4e471a7471ed2 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Wed, 2 Oct 2019 19:35:58 -0500 Subject: [PATCH 11/61] MC-17518: Cart Rest API not showing all shipping assignments for multi-shipping --- .../DisableMultishippingMode.php} | 4 +- ...n.php => MultishippingQuoteRepository.php} | 4 +- ...tPlugin.php => ResetShippingAssigment.php} | 2 +- .../DisableMultishippingModeTest.php} | 10 +- app/code/Magento/Multishipping/etc/di.xml | 2 +- .../Magento/Multishipping/etc/frontend/di.xml | 8 +- .../Multishipping/Api/CartRepositoryTest.php | 139 ++++++++++++++++++ .../Magento/Quote/Api/CartRepositoryTest.php | 46 ------ 8 files changed, 154 insertions(+), 61 deletions(-) rename app/code/Magento/Multishipping/{Controller/Checkout/Plugin.php => Plugin/DisableMultishippingMode.php} (93%) rename app/code/Magento/Multishipping/Plugin/{MultishippingQuoteRepositoryPlugin.php => MultishippingQuoteRepository.php} (98%) rename app/code/Magento/Multishipping/Plugin/{ResetShippingAssigmentPlugin.php => ResetShippingAssigment.php} (97%) rename app/code/Magento/Multishipping/Test/Unit/{Controller/Checkout/PluginTest.php => Plugin/DisableMultishippingModeTest.php} (91%) create mode 100644 dev/tests/api-functional/testsuite/Magento/Multishipping/Api/CartRepositoryTest.php diff --git a/app/code/Magento/Multishipping/Controller/Checkout/Plugin.php b/app/code/Magento/Multishipping/Plugin/DisableMultishippingMode.php similarity index 93% rename from app/code/Magento/Multishipping/Controller/Checkout/Plugin.php rename to app/code/Magento/Multishipping/Plugin/DisableMultishippingMode.php index f60feb2b834b..fff2346d7624 100644 --- a/app/code/Magento/Multishipping/Controller/Checkout/Plugin.php +++ b/app/code/Magento/Multishipping/Plugin/DisableMultishippingMode.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\Multishipping\Controller\Checkout; +namespace Magento\Multishipping\Plugin; use Magento\Checkout\Model\Cart; use Magento\Framework\App\Action\Action; @@ -13,7 +13,7 @@ /** * Turns Off Multishipping mode for Quote. */ -class Plugin +class DisableMultishippingMode { /** * @var Cart diff --git a/app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepositoryPlugin.php b/app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepository.php similarity index 98% rename from app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepositoryPlugin.php rename to app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepository.php index db972cf9bd7c..af19e4bc91f5 100644 --- a/app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepositoryPlugin.php +++ b/app/code/Magento/Multishipping/Plugin/MultishippingQuoteRepository.php @@ -15,9 +15,9 @@ use Magento\Quote\Model\ShippingAssignmentFactory; /** - * Plugin for multishipping quote processing in WebAPI. + * Plugin for multishipping quote processing. */ -class MultishippingQuoteRepositoryPlugin +class MultishippingQuoteRepository { /** * @var ShippingAssignmentFactory diff --git a/app/code/Magento/Multishipping/Plugin/ResetShippingAssigmentPlugin.php b/app/code/Magento/Multishipping/Plugin/ResetShippingAssigment.php similarity index 97% rename from app/code/Magento/Multishipping/Plugin/ResetShippingAssigmentPlugin.php rename to app/code/Magento/Multishipping/Plugin/ResetShippingAssigment.php index 376dbf723b88..deac19e23a23 100644 --- a/app/code/Magento/Multishipping/Plugin/ResetShippingAssigmentPlugin.php +++ b/app/code/Magento/Multishipping/Plugin/ResetShippingAssigment.php @@ -13,7 +13,7 @@ /** * Resets quote shipping assignments when item is removed from multishipping quote. */ -class ResetShippingAssigmentPlugin +class ResetShippingAssigment { /** * @var ShippingAssignmentProcessor diff --git a/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php b/app/code/Magento/Multishipping/Test/Unit/Plugin/DisableMultishippingModeTest.php similarity index 91% rename from app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php rename to app/code/Magento/Multishipping/Test/Unit/Plugin/DisableMultishippingModeTest.php index 5397317ca299..96aa364c3873 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Controller/Checkout/PluginTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Plugin/DisableMultishippingModeTest.php @@ -10,15 +10,15 @@ use Magento\Checkout\Controller\Index\Index; use Magento\Checkout\Model\Cart; -use Magento\Multishipping\Controller\Checkout\Plugin; +use Magento\Multishipping\Plugin\DisableMultishippingMode; use Magento\Quote\Api\Data\CartExtensionInterface; use Magento\Quote\Api\Data\ShippingAssignmentInterface; use Magento\Quote\Model\Quote; /** - * Class PluginTest + * Class DisableMultishippingModeTest */ -class PluginTest extends \PHPUnit\Framework\TestCase +class DisableMultishippingModeTest extends \PHPUnit\Framework\TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject @@ -31,7 +31,7 @@ class PluginTest extends \PHPUnit\Framework\TestCase private $quoteMock; /** - * @var Plugin + * @var DisableMultishippingMode */ private $object; @@ -48,7 +48,7 @@ protected function setUp() $this->cartMock->expects($this->once()) ->method('getQuote') ->will($this->returnValue($this->quoteMock)); - $this->object = new \Magento\Multishipping\Controller\Checkout\Plugin($this->cartMock); + $this->object = new DisableMultishippingMode($this->cartMock); } /** diff --git a/app/code/Magento/Multishipping/etc/di.xml b/app/code/Magento/Multishipping/etc/di.xml index 993376da8378..ad0d341d6b2e 100644 --- a/app/code/Magento/Multishipping/etc/di.xml +++ b/app/code/Magento/Multishipping/etc/di.xml @@ -10,6 +10,6 @@ <plugin name="multishipping_shipping_addresses" type="Magento\Multishipping\Model\Cart\CartTotalRepositoryPlugin" /> </type> <type name="Magento\Quote\Model\QuoteRepository"> - <plugin name="multishipping_quote_repository" type="Magento\Multishipping\Plugin\MultishippingQuoteRepositoryPlugin" /> + <plugin name="multishipping_quote_repository" type="Magento\Multishipping\Plugin\MultishippingQuoteRepository" /> </type> </config> diff --git a/app/code/Magento/Multishipping/etc/frontend/di.xml b/app/code/Magento/Multishipping/etc/frontend/di.xml index 3d85f4c8a447..481b95280a4a 100644 --- a/app/code/Magento/Multishipping/etc/frontend/di.xml +++ b/app/code/Magento/Multishipping/etc/frontend/di.xml @@ -31,13 +31,13 @@ </arguments> </type> <type name="Magento\Checkout\Controller\Cart\Add"> - <plugin name="multishipping_disabler" type="Magento\Multishipping\Controller\Checkout\Plugin" sortOrder="50" /> + <plugin name="multishipping_disabler" type="Magento\Multishipping\Plugin\DisableMultishippingMode" sortOrder="50" /> </type> <type name="Magento\Checkout\Controller\Cart\UpdatePost"> - <plugin name="multishipping_disabler" type="Magento\Multishipping\Controller\Checkout\Plugin" sortOrder="50" /> + <plugin name="multishipping_disabler" type="Magento\Multishipping\Plugin\DisableMultishippingMode" sortOrder="50" /> </type> <type name="Magento\Checkout\Controller\Index\Index"> - <plugin name="multishipping_disabler" type="Magento\Multishipping\Controller\Checkout\Plugin" sortOrder="50" /> + <plugin name="multishipping_disabler" type="Magento\Multishipping\Plugin\DisableMultishippingMode" sortOrder="50" /> </type> <type name="Magento\Checkout\Model\Cart"> <plugin name="multishipping_session_mapper" type="Magento\Multishipping\Model\Checkout\Type\Multishipping\Plugin" sortOrder="50" /> @@ -46,6 +46,6 @@ <plugin name="multishipping_clear_addresses" type="Magento\Multishipping\Model\Cart\Controller\CartPlugin" sortOrder="50" /> </type> <type name="Magento\Quote\Model\Quote"> - <plugin name="multishipping_reset_shipping_assigment" type="Magento\Multishipping\Plugin\ResetShippingAssigmentPlugin"/> + <plugin name="multishipping_reset_shipping_assigment" type="Magento\Multishipping\Plugin\ResetShippingAssigment"/> </type> </config> diff --git a/dev/tests/api-functional/testsuite/Magento/Multishipping/Api/CartRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Multishipping/Api/CartRepositoryTest.php new file mode 100644 index 000000000000..46844438fdd9 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/Multishipping/Api/CartRepositoryTest.php @@ -0,0 +1,139 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Multishipping\Api; + +use Magento\Framework\Api\FilterBuilder; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SortOrderBuilder; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\Quote; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\TestCase\WebapiAbstract; + +/** + * Tests web-api for multishipping quote. + */ +class CartRepositoryTest extends WebapiAbstract +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + + /** + * @var SortOrderBuilder + */ + private $sortOrderBuilder; + + /** + * @var FilterBuilder + */ + private $filterBuilder; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->filterBuilder = $this->objectManager->create(FilterBuilder::class); + $this->sortOrderBuilder = $this->objectManager->create(SortOrderBuilder::class); + $this->searchCriteriaBuilder = $this->objectManager->create(SearchCriteriaBuilder::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + try { + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class); + $cart = $this->getCart('multishipping_quote_id'); + $quoteRepository->delete($cart); + } catch (\InvalidArgumentException $e) { + // Do nothing if cart fixture was not used + } + parent::tearDown(); + } + + /** + * Tests that multishipping quote contains all addresses in shipping assignments. + * + * @magentoApiDataFixture Magento/Multishipping/Fixtures/quote_with_split_items.php + */ + public function testGetMultishippingCart() + { + $cart = $this->getCart('multishipping_quote_id'); + $cartId = $cart->getId(); + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/carts/' . $cartId, + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + ], + 'soap' => [ + 'service' => 'quoteCartRepositoryV1', + 'serviceVersion' => 'V1', + 'operation' => 'quoteCartRepositoryV1Get', + ], + ]; + + $requestData = ['cartId' => $cartId]; + $cartData = $this->_webApiCall($serviceInfo, $requestData); + + $shippingAssignments = $cart->getExtensionAttributes()->getShippingAssignments(); + foreach ($shippingAssignments as $key => $shippingAssignment) { + $address = $shippingAssignment->getShipping()->getAddress(); + $cartItem = $shippingAssignment->getItems()[0]; + $this->assertEquals( + $address->getId(), + $cartData['extension_attributes']['shipping_assignments'][$key]['shipping']['address']['id'] + ); + $this->assertEquals( + $cartItem->getSku(), + $cartData['extension_attributes']['shipping_assignments'][$key]['items'][0]['sku'] + ); + $this->assertEquals( + $cartItem->getQty(), + $cartData['extension_attributes']['shipping_assignments'][$key]['items'][0]['qty'] + ); + } + } + + /** + * Retrieve quote by given reserved order ID + * + * @param string $reservedOrderId + * @return Quote + * @throws \InvalidArgumentException + */ + private function getCart(string $reservedOrderId): Quote + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class); + $items = $quoteRepository->getList($searchCriteria)->getItems(); + + if (empty($items)) { + throw new \InvalidArgumentException('There is no quote with provided reserved order ID.'); + } + + return array_pop($items); + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php index 7ffc4311e40e..5a894758dc9e 100644 --- a/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Quote/Api/CartRepositoryTest.php @@ -66,8 +66,6 @@ protected function tearDown() $quoteRepository = $this->objectManager->get(CartRepositoryInterface::class); $cart = $this->getCart('test01'); $quoteRepository->delete($cart); - $cart = $this->getCart('multishipping_quote_id'); - $quoteRepository->delete($cart); } catch (\InvalidArgumentException $e) { // Do nothing if cart fixture was not used } @@ -145,50 +143,6 @@ public function testGetCart() $this->assertEquals($cart->getStoreToQuoteRate(), $cartData['currency']['store_to_quote_rate']); } - /** - * Tests that multishipping quote contains all addresses in shipping assignments. - * - * @magentoApiDataFixture Magento/Multishipping/Fixtures/quote_with_split_items.php - */ - public function testGetMultishippingCart() - { - $cart = $this->getCart('multishipping_quote_id'); - $cartId = $cart->getId(); - - $serviceInfo = [ - 'rest' => [ - 'resourcePath' => '/V1/carts/' . $cartId, - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, - ], - 'soap' => [ - 'service' => 'quoteCartRepositoryV1', - 'serviceVersion' => 'V1', - 'operation' => 'quoteCartRepositoryV1Get', - ], - ]; - - $requestData = ['cartId' => $cartId]; - $cartData = $this->_webApiCall($serviceInfo, $requestData); - - $shippingAssignments = $cart->getExtensionAttributes()->getShippingAssignments(); - foreach ($shippingAssignments as $key => $shippingAssignment) { - $address = $shippingAssignment->getShipping()->getAddress(); - $cartItem = $shippingAssignment->getItems()[0]; - $this->assertEquals( - $address->getId(), - $cartData['extension_attributes']['shipping_assignments'][$key]['shipping']['address']['id'] - ); - $this->assertEquals( - $cartItem->getSku(), - $cartData['extension_attributes']['shipping_assignments'][$key]['items'][0]['sku'] - ); - $this->assertEquals( - $cartItem->getQty(), - $cartData['extension_attributes']['shipping_assignments'][$key]['items'][0]['qty'] - ); - } - } - /** * Tests exception when cartId is not provided. * From ecd52b945c28bad14267c31f14e1284d55b5ce6b Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Thu, 3 Oct 2019 12:09:09 -0500 Subject: [PATCH 12/61] MC-15986: Category Filtering - added resolver changes for category list query --- .../Model/Category/CategoryFilter.php | 29 ++++++------------ .../Model/Resolver/CategoryList.php | 30 +++++-------------- .../CatalogGraphQl/etc/schema.graphqls | 2 +- 3 files changed, 18 insertions(+), 43 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php index 574f5dd2715c..5058bb2e07c6 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php +++ b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php @@ -5,10 +5,9 @@ */ declare(strict_types=1); -namespace Magento\CatalogGraphQl\Model\Category;; +namespace Magento\CatalogGraphQl\Model\Category; use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; -use Magento\Catalog\Api\CategoryRepositoryInterface; /** * Category filter allows to filter collection using 'id, url_key, name' from search criteria. @@ -21,19 +20,11 @@ class CategoryFilter private $collectionFactory; /** - * @var CategoryRepositoryInterface - */ - private $categoryRepository; - - /** - * @param CategoryRepositoryInterface $categoryRepository; * @param CollectionFactory $collectionFactory */ public function __construct( - CategoryRepositoryInterface $categoryRepository, CollectionFactory $collectionFactory ) { - $this->categoryRepository = $categoryRepository; $this->collectionFactory = $collectionFactory; } @@ -41,15 +32,14 @@ public function __construct( * Filter for filtering the requested categories id's based on url_key, ids, name in the result. * * @param array $args - * - * @return array|int + * @return array */ - public function applyFilters(array $args) + public function applyFilters(array $args): array { $categoryCollection = $this->collectionFactory->create(); - foreach($args['filters'] as $field => $cond){ - foreach($cond as $condType => $value){ - if($field === 'ids'){ + foreach ($args['filters'] as $field => $cond) { + foreach ($cond as $condType => $value) { + if ($field === 'ids') { $categoryCollection->addIdFilter($value); } else { $categoryCollection->addAttributeToFilter($field, [$condType => $value]); @@ -57,10 +47,9 @@ public function applyFilters(array $args) } } $categoryIds = []; - $categoriesData = $categoryCollection->getData(); - foreach ($categoriesData as $categoryData){ - $categoryIds[] = (int)$categoryData['entity_id']; + foreach ($categoryCollection as $category) { + $categoryIds[] = (int)$category->getId(); } - return $categoryIds; + return $categoryIds; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php index 932b88c68f1f..2511e07dc4f8 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php @@ -14,20 +14,14 @@ use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\CategoryTree; use Magento\CatalogGraphQl\Model\Category\CategoryFilter; /** - * Category tree resolver, used for GraphQL category data request processing. + * Category List resolver, used for GraphQL category data request processing. */ class CategoryList implements ResolverInterface { - /** - * Name of type in GraphQL - */ - const CATEGORY_INTERFACE = 'CategoryInterface'; - /** * @var CategoryTree */ @@ -76,30 +70,22 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value } if (!isset($args['filters'])) { - throw new GraphQlInputException( - __( "'filters' input argument is required.") - ); + $rootCategoryIds = [(int)$context->getExtensionAttributes()->getStore()->getRootCategoryId()]; + } else { + $rootCategoryIds = $this->categoryFilter->applyFilters($args); } - $rootCategoryIds = $this->categoryFilter->applyFilters($args); $result = []; - $categoriesTreeData = []; - foreach ($rootCategoryIds as $rootCategoryId) { if ($rootCategoryId !== Category::TREE_ROOT_ID) { $this->checkCategoryIsActive->execute($rootCategoryId); } - $categoriesTree = $this->categoryTree->getTree($info, $rootCategoryId); - - if (empty($categoriesTree) || ($categoriesTree->count() == 0)) { + $categoryTree = $this->categoryTree->getTree($info, $rootCategoryId); + if (empty($categoryTree)) { throw new GraphQlNoSuchEntityException(__('Category doesn\'t exist')); } - $categoriesTreeData[] = $categoriesTree; - } - - foreach ($categoriesTreeData as $treeData ) { - $result[] = $this->extractDataFromCategoryTree->execute($treeData); + $result[] = current($this->extractDataFromCategoryTree->execute($categoryTree)); } - return current($result); + return $result; } } diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 0cc3901a1f07..9c729a175ad0 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -129,7 +129,7 @@ type CustomizableAreaValue @doc(description: "CustomizableAreaValue defines the max_characters: Int @doc(description: "The maximum number of characters that can be entered for this customizable option.") } -type CategoryTree implements CategoryInterface @doc(description: "An array containing the filtered categories and their subcategories") { +type CategoryTree implements CategoryInterface @doc(description: "Category Tree implementation.") { children: [CategoryTree] @doc(description: "Child categories tree.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") } From d015409302077afc9943449b743a398714e62958 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Thu, 3 Oct 2019 13:39:02 -0500 Subject: [PATCH 13/61] MC-17518: Cart Rest API not showing all shipping assignments for multi-shipping -Fix namespace --- .../Test/Unit/Plugin/DisableMultishippingModeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Multishipping/Test/Unit/Plugin/DisableMultishippingModeTest.php b/app/code/Magento/Multishipping/Test/Unit/Plugin/DisableMultishippingModeTest.php index 96aa364c3873..02ae1a70ce80 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Plugin/DisableMultishippingModeTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Plugin/DisableMultishippingModeTest.php @@ -6,7 +6,7 @@ */ declare(strict_types=1); -namespace Magento\Multishipping\Test\Unit\Controller\Checkout; +namespace Magento\Multishipping\Test\Unit\Plugin; use Magento\Checkout\Controller\Index\Index; use Magento\Checkout\Model\Cart; From be5455a58240b57e4dc0c44a5cea2bb5a2e01c57 Mon Sep 17 00:00:00 2001 From: Roman Lytvynenko <lytvynen@adobe.com> Date: Thu, 3 Oct 2019 13:51:17 -0500 Subject: [PATCH 14/61] MC-21481: TransportBuilder doesn't add "to" email-addresses, if given in array --- .../Magento/Framework/Mail/Template/TransportBuilder.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php b/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php index 4a8d6572faaf..f2f61cfd7ef1 100644 --- a/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php +++ b/lib/internal/Magento/Framework/Mail/Template/TransportBuilder.php @@ -427,6 +427,8 @@ private function addAddressByType(string $addressType, $email, ?string $name = n $this->messageData[$addressType], $convertedAddressArray ); + } else { + $this->messageData[$addressType] = $convertedAddressArray; } } } From f6446259cea26f20c9f2471b86127af136c3352c Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Thu, 3 Oct 2019 17:24:52 -0500 Subject: [PATCH 15/61] MC-15986: Category Filtering - added resolver changes on filter --- .../Model/Category/CategoryFilter.php | 18 +++++++-------- .../Model/Resolver/CategoryList.php | 23 ++++++++++++++++--- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php index 5058bb2e07c6..42f35a871185 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php +++ b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php @@ -32,24 +32,24 @@ public function __construct( * Filter for filtering the requested categories id's based on url_key, ids, name in the result. * * @param array $args - * @return array + * @param \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection + * @return bool */ - public function applyFilters(array $args): array - { - $categoryCollection = $this->collectionFactory->create(); + public function applyFilters( + array $args, + \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection + ): bool { foreach ($args['filters'] as $field => $cond) { foreach ($cond as $condType => $value) { if ($field === 'ids') { $categoryCollection->addIdFilter($value); + } elseif ($condType === 'match') { + $categoryCollection->addAttributeToFilter($field, ['like' => "%{$value}%"]); } else { $categoryCollection->addAttributeToFilter($field, [$condType => $value]); } } } - $categoryIds = []; - foreach ($categoryCollection as $category) { - $categoryIds[] = (int)$category->getId(); - } - return $categoryIds; + return true; } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php index 2511e07dc4f8..140cb68be679 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php @@ -16,6 +16,7 @@ use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\CategoryTree; use Magento\CatalogGraphQl\Model\Category\CategoryFilter; +use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; /** * Category List resolver, used for GraphQL category data request processing. @@ -27,6 +28,11 @@ class CategoryList implements ResolverInterface */ private $categoryTree; + /** + * @var CollectionFactory + */ + private $collectionFactory; + /** * @var CategoryFilter */ @@ -47,17 +53,20 @@ class CategoryList implements ResolverInterface * @param ExtractDataFromCategoryTree $extractDataFromCategoryTree * @param CheckCategoryIsActive $checkCategoryIsActive * @param CategoryFilter $categoryFilter + * @param CollectionFactory $collectionFactory */ public function __construct( CategoryTree $categoryTree, ExtractDataFromCategoryTree $extractDataFromCategoryTree, CheckCategoryIsActive $checkCategoryIsActive, - CategoryFilter $categoryFilter + CategoryFilter $categoryFilter, + CollectionFactory $collectionFactory ) { $this->categoryTree = $categoryTree; $this->extractDataFromCategoryTree = $extractDataFromCategoryTree; $this->checkCategoryIsActive = $checkCategoryIsActive; $this->categoryFilter = $categoryFilter; + $this->collectionFactory = $collectionFactory; } /** @@ -69,10 +78,18 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value return $value[$field->getName()]; } + $categoryCollection = $this->collectionFactory->create(); + $categoryCollection->addAttributeToFilter('is_active', 1); + $categoryCollection->addAttributeToSelect(['name','url_key', 'ids']); + if (!isset($args['filters'])) { $rootCategoryIds = [(int)$context->getExtensionAttributes()->getStore()->getRootCategoryId()]; } else { - $rootCategoryIds = $this->categoryFilter->applyFilters($args); + $this->categoryFilter->applyFilters($args, $categoryCollection); + $rootCategoryIds = []; + foreach ($categoryCollection as $category) { + $rootCategoryIds[] = (int)$category->getId(); + } } $result = []; @@ -81,7 +98,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $this->checkCategoryIsActive->execute($rootCategoryId); } $categoryTree = $this->categoryTree->getTree($info, $rootCategoryId); - if (empty($categoryTree)) { + if (empty($categoryTree) || ($categoryTree->count() == 0)) { throw new GraphQlNoSuchEntityException(__('Category doesn\'t exist')); } $result[] = current($this->extractDataFromCategoryTree->execute($categoryTree)); From b66bafe743204efe0c6b56b48d9c602e18e58ad6 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Thu, 3 Oct 2019 16:18:36 -0500 Subject: [PATCH 16/61] MC-21467: Reorder from admin throws an error when adding products - Fix return key press in products grid filter submits the "create order" form in admin --- .../view/adminhtml/templates/widget/grid.phtml | 3 +++ .../adminhtml/templates/widget/grid/extended.phtml | 3 +++ .../Gateway/Validator/ErrorCodeProvider.php | 13 ++++++++----- .../Block/Adminhtml/Order/Create/Search/Grid.php | 12 ++++++------ .../view/adminhtml/web/order/create/scripts.js | 14 ++++++++++++++ lib/web/mage/adminhtml/grid.js | 5 +++++ 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml index b712bc6c9531..7f6f2bbd13fa 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml @@ -170,6 +170,9 @@ $numColumns = $block->getColumns() !== null ? count($block->getColumns()) : 0; <?php if ($block->getSortableUpdateCallback()) : ?> <?= $block->escapeJs($block->getJsObjectName()) ?>.sortableUpdateCallback = <?= /* @noEscape */ $block->getSortableUpdateCallback() ?>; <?php endif; ?> + <?php if ($block->getFilterKeyPressCallback()) : ?> + <?= $block->escapeJs($block->getJsObjectName()) ?>.filterKeyPressCallback = <?= /* @noEscape */ $block->getFilterKeyPressCallback() ?>; + <?php endif; ?> <?= $block->escapeJs($block->getJsObjectName()) ?>.bindSortable(); <?php if ($block->getRowInitCallback()) : ?> <?= $block->escapeJs($block->getJsObjectName()) ?>.initRowCallback = <?= /* @noEscape */ $block->getRowInitCallback() ?>; diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml index 0bb453f25d7c..527ddc436207 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid/extended.phtml @@ -272,6 +272,9 @@ $numColumns = count($block->getColumns()); <?php if ($block->getCheckboxCheckCallback()) : ?> <?= $block->escapeJs($block->getJsObjectName()) ?>.checkboxCheckCallback = <?= /* @noEscape */ $block->getCheckboxCheckCallback() ?>; <?php endif; ?> + <?php if ($block->getFilterKeyPressCallback()) : ?> + <?= $block->escapeJs($block->getJsObjectName()) ?>.filterKeyPressCallback = <?= /* @noEscape */ $block->getFilterKeyPressCallback() ?>; + <?php endif; ?> <?php if ($block->getRowInitCallback()) : ?> <?= $block->escapeJs($block->getJsObjectName()) ?>.initRowCallback = <?= /* @noEscape */ $block->getRowInitCallback() ?>; <?= $block->escapeJs($block->getJsObjectName()) ?>.initGridRows(); diff --git a/app/code/Magento/Braintree/Gateway/Validator/ErrorCodeProvider.php b/app/code/Magento/Braintree/Gateway/Validator/ErrorCodeProvider.php index 58ce33305da8..2f73dd8f380d 100644 --- a/app/code/Magento/Braintree/Gateway/Validator/ErrorCodeProvider.php +++ b/app/code/Magento/Braintree/Gateway/Validator/ErrorCodeProvider.php @@ -11,6 +11,7 @@ use Braintree\Error\Validation; use Braintree\Result\Error; use Braintree\Result\Successful; +use Braintree\Transaction; /** * Processes errors codes from Braintree response. @@ -38,12 +39,14 @@ public function getErrorCodes($response): array $result[] = $error->code; } - if (isset($response->transaction) && $response->transaction->status === 'gateway_rejected') { - $result[] = $response->transaction->gatewayRejectionReason; - } + if (isset($response->transaction) && $response->transaction) { + if ($response->transaction->status === Transaction::GATEWAY_REJECTED) { + $result[] = $response->transaction->gatewayRejectionReason; + } - if (isset($response->transaction) && $response->transaction->status === 'processor_declined') { - $result[] = $response->transaction->processorResponseCode; + if ($response->transaction->status === Transaction::PROCESSOR_DECLINED) { + $result[] = $response->transaction->processorResponseCode; + } } return $result; diff --git a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php index 9a271f741edd..001c581dc0da 100644 --- a/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php +++ b/app/code/Magento/Sales/Block/Adminhtml/Order/Create/Search/Grid.php @@ -5,8 +5,7 @@ */ namespace Magento\Sales\Block\Adminhtml\Order\Create\Search; -use Magento\Sales\Block\Adminhtml\Order\Create\Search\Grid\DataProvider\ProductCollection - as ProductCollectionDataProvider; +use Magento\Sales\Block\Adminhtml\Order\Create\Search\Grid\DataProvider\ProductCollection; use Magento\Framework\App\ObjectManager; /** @@ -48,7 +47,7 @@ class Grid extends \Magento\Backend\Block\Widget\Grid\Extended protected $_productFactory; /** - * @var ProductCollectionDataProvider $productCollectionProvider + * @var ProductCollection $productCollectionProvider */ private $productCollectionProvider; @@ -60,7 +59,7 @@ class Grid extends \Magento\Backend\Block\Widget\Grid\Extended * @param \Magento\Backend\Model\Session\Quote $sessionQuote * @param \Magento\Sales\Model\Config $salesConfig * @param array $data - * @param ProductCollectionDataProvider|null $productCollectionProvider + * @param ProductCollection|null $productCollectionProvider */ public function __construct( \Magento\Backend\Block\Template\Context $context, @@ -70,14 +69,14 @@ public function __construct( \Magento\Backend\Model\Session\Quote $sessionQuote, \Magento\Sales\Model\Config $salesConfig, array $data = [], - ProductCollectionDataProvider $productCollectionProvider = null + ProductCollection $productCollectionProvider = null ) { $this->_productFactory = $productFactory; $this->_catalogConfig = $catalogConfig; $this->_sessionQuote = $sessionQuote; $this->_salesConfig = $salesConfig; $this->productCollectionProvider = $productCollectionProvider - ?: ObjectManager::getInstance()->get(ProductCollectionDataProvider::class); + ?: ObjectManager::getInstance()->get(ProductCollection::class); parent::__construct($context, $backendHelper, $data); } @@ -94,6 +93,7 @@ protected function _construct() $this->setCheckboxCheckCallback('order.productGridCheckboxCheck.bind(order)'); $this->setRowInitCallback('order.productGridRowInit.bind(order)'); $this->setDefaultSort('entity_id'); + $this->setFilterKeyPressCallback('order.productGridFilterKeyPress'); $this->setUseAjax(true); if ($this->getRequest()->getParam('collapse')) { $this->setIsCollapsed(true); diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js index 3fe9d0878288..4e0741451074 100644 --- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js +++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js @@ -795,6 +795,20 @@ define([ grid.reloadParams = {'products[]':this.gridProducts.keys()}; }, + productGridFilterKeyPress: function (grid, event) { + var returnKey = parseInt(Event.KEY_RETURN || 13, 10); + + if (event.keyCode === returnKey) { + if (typeof event.stopPropagation === 'function') { + event.stopPropagation(); + } + + if (typeof event.preventDefault === 'function') { + event.preventDefault(); + } + } + }, + /** * Submit configured products to quote */ diff --git a/lib/web/mage/adminhtml/grid.js b/lib/web/mage/adminhtml/grid.js index 1c9319f95a64..28bdb96e5cdb 100644 --- a/lib/web/mage/adminhtml/grid.js +++ b/lib/web/mage/adminhtml/grid.js @@ -63,6 +63,7 @@ define([ this.initRowCallback = false; this.doFilterCallback = false; this.sortableUpdateCallback = false; + this.filterKeyPressCallback = false; this.reloadParams = false; @@ -511,6 +512,10 @@ define([ if (event.keyCode == Event.KEY_RETURN) { //eslint-disable-line eqeqeq this.doFilter(); } + + if (this.filterKeyPressCallback) { + this.filterKeyPressCallback(this, event); + } }, /** From 43b3924ec974015f520c3cc7ef0581cbee4cba97 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Fri, 4 Oct 2019 12:10:20 -0500 Subject: [PATCH 17/61] MC-21459: Check/Money Order Language in Admin order view is always from Default Store View --- .../view/adminhtml/templates/info/checkmo.phtml | 3 ++- .../view/adminhtml/templates/info/pdf/checkmo.phtml | 3 ++- .../view/adminhtml/templates/info/purchaseorder.phtml | 3 ++- .../Payment/view/adminhtml/templates/info/default.phtml | 3 ++- .../Payment/view/adminhtml/templates/info/pdf/default.phtml | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml index 36f9d35327fc..28395f8eeb84 100644 --- a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml +++ b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/checkmo.phtml @@ -7,8 +7,9 @@ /** * @var $block \Magento\OfflinePayments\Block\Info\Checkmo */ +$paymentTitle = $block->getMethod()->getConfigData('title', $block->getInfo()->getOrder()->getStoreId()); ?> -<?= $block->escapeHtml($block->getMethod()->getTitle()) ?> +<?= $block->escapeHtml($paymentTitle) ?> <?php if ($block->getInfo()->getAdditionalInformation()) : ?> <?php if ($block->getPayableTo()) : ?> <br /><?= $block->escapeHtml(__('Make Check payable to: %1', $block->getPayableTo())) ?> diff --git a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml index d8d952526e67..f85a8f8357dd 100644 --- a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml +++ b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/pdf/checkmo.phtml @@ -7,8 +7,9 @@ /** * @var $block \Magento\OfflinePayments\Block\Info\Checkmo */ +$paymentTitle = $block->getMethod()->getConfigData('title', $block->getInfo()->getOrder()->getStoreId()); ?> -<?= $block->escapeHtml($block->getMethod()->getTitle()) ?> +<?= $block->escapeHtml($paymentTitle) ?> {{pdf_row_separator}} <?php if ($block->getInfo()->getAdditionalInformation()) : ?> {{pdf_row_separator}} diff --git a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/purchaseorder.phtml b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/purchaseorder.phtml index 2a6de7f0cc35..ae7f654a1350 100644 --- a/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/purchaseorder.phtml +++ b/app/code/Magento/OfflinePayments/view/adminhtml/templates/info/purchaseorder.phtml @@ -6,8 +6,9 @@ /** * @var $block \Magento\OfflinePayments\Block\Info\Purchaseorder */ +$paymentTitle = $block->getMethod()->getConfigData('title', $block->getInfo()->getOrder()->getStoreId()); ?> -<div class="order-payment-method-name"><?= $block->escapeHtml($block->getMethod()->getTitle()) ?></div> +<div class="order-payment-method-name"><?= $block->escapeHtml($paymentTitle) ?></div> <table class="data-table admin__table-secondary"> <tr> <th><?= $block->escapeHtml(__('Purchase Order Number')) ?>:</th> diff --git a/app/code/Magento/Payment/view/adminhtml/templates/info/default.phtml b/app/code/Magento/Payment/view/adminhtml/templates/info/default.phtml index 8b9c37f11256..3cd88bddbfb1 100644 --- a/app/code/Magento/Payment/view/adminhtml/templates/info/default.phtml +++ b/app/code/Magento/Payment/view/adminhtml/templates/info/default.phtml @@ -9,8 +9,9 @@ * @see \Magento\Payment\Block\Info */ $specificInfo = $block->getSpecificInformation(); +$paymentTitle = $block->getMethod()->getConfigData('title', $block->getInfo()->getOrder()->getStoreId()); ?> -<?= $block->escapeHtml($block->getMethod()->getTitle()) ?> +<?= $block->escapeHtml($paymentTitle) ?> <?php if ($specificInfo) : ?> <table class="data-table admin__table-secondary"> diff --git a/app/code/Magento/Payment/view/adminhtml/templates/info/pdf/default.phtml b/app/code/Magento/Payment/view/adminhtml/templates/info/pdf/default.phtml index a8583ea5549f..54b9e48d07a9 100644 --- a/app/code/Magento/Payment/view/adminhtml/templates/info/pdf/default.phtml +++ b/app/code/Magento/Payment/view/adminhtml/templates/info/pdf/default.phtml @@ -8,8 +8,9 @@ * @see \Magento\Payment\Block\Info * @var \Magento\Payment\Block\Info $block */ +$paymentTitle = $block->getMethod()->getConfigData('title', $block->getInfo()->getOrder()->getStoreId()); ?> -<?= $block->escapeHtml($block->getMethod()->getTitle()) ?>{{pdf_row_separator}} +<?= $block->escapeHtml($paymentTitle) ?>{{pdf_row_separator}} <?php if ($specificInfo = $block->getSpecificInformation()) : ?> <?php foreach ($specificInfo as $label => $value) : ?> From f582c7598251002b5f3ee62c6762cda7f8cfa6d8 Mon Sep 17 00:00:00 2001 From: Roman Lytvynenko <lytvynen@adobe.com> Date: Fri, 4 Oct 2019 14:35:19 -0500 Subject: [PATCH 18/61] MC-21481: TransportBuilder doesn't add "to" email-addresses, if given in array --- .../Mail/Template/TransportBuilderMock.php | 3 +- .../Mail/TransportInterfaceMock.php | 11 +- .../Email/Model/_files/email_template.php | 6 +- .../Framework/Mail/TransportBuilderTest.php | 100 ++++++++++++++++++ 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Mail/TransportBuilderTest.php diff --git a/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php b/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php index 9f697a1be633..3f236821b24a 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php @@ -38,11 +38,12 @@ public function getSentMessage() * Return transport mock. * * @return \Magento\TestFramework\Mail\TransportInterfaceMock + * @throws \Magento\Framework\Exception\LocalizedException */ public function getTransport() { $this->prepareMessage(); $this->reset(); - return new \Magento\TestFramework\Mail\TransportInterfaceMock(); + return new \Magento\TestFramework\Mail\TransportInterfaceMock($this->message); } } diff --git a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php index 8f967b501a59..58f031813b48 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php @@ -8,6 +8,13 @@ class TransportInterfaceMock implements \Magento\Framework\Mail\TransportInterface { + private $message; + + public function __construct($message = '') + { + $this->message = $message; + } + /** * Mock of send a mail using transport * @@ -21,10 +28,10 @@ public function sendMessage() /** * Get message * - * @return string + * @return mixed */ public function getMessage() { - return ''; + return $this->message; } } diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php b/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php index bbbcc3133d4b..6d5f760d7894 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/email_template.php @@ -10,9 +10,9 @@ $template->setOptions(['area' => 'test area', 'store' => 1]); $template->setData( [ - 'template_text' => - file_get_contents(__DIR__ . '/template_fixture.html'), - 'template_code' => \Magento\Theme\Model\Config\ValidatorTest::TEMPLATE_CODE + 'template_text' => file_get_contents(__DIR__ . '/template_fixture.html'), + 'template_code' => \Magento\Theme\Model\Config\ValidatorTest::TEMPLATE_CODE, + 'template_type' => \Magento\Email\Model\Template::TYPE_TEXT ] ); $template->save(); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Mail/TransportBuilderTest.php b/dev/tests/integration/testsuite/Magento/Framework/Mail/TransportBuilderTest.php new file mode 100644 index 000000000000..03bdc9a36552 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Mail/TransportBuilderTest.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Framework\Mail; + +use Magento\Email\Model\BackendTemplate; +use Magento\Email\Model\Template; +use Magento\Framework\Mail\Template\TransportBuilder; +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Class EmailMessageTest + */ +class TransportBuilderTest extends TestCase +{ + /** + * @var ObjectManagerInterface + */ + private $di; + + /** + * @var TransportBuilder + */ + protected $builder; + + /** + * @var Template + */ + protected $template; + + protected function setUp() + { + $this->di = Bootstrap::getObjectManager(); + $this->builder = $this->di->get(TransportBuilder::class); + $this->template = $this->di->get(Template::class); + } + + /** + * @magentoDataFixture Magento/Email/Model/_files/email_template.php + * @magentoDbIsolation enabled + * + * @param string|array $email + * @dataProvider emailDataProvider + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function testAddToEmail($email) + { + $templateId = $this->template->load('email_exception_fixture', 'template_code')->getId(); + + $this->builder->setTemplateModel(BackendTemplate::class); + + $vars = ['reason' => 'Reason', 'customer' => 'Customer']; + $options = ['area' => 'frontend', 'store' => 1]; + $this->builder->setTemplateIdentifier($templateId)->setTemplateVars($vars)->setTemplateOptions($options); + + $this->builder->addTo($email); + + /** @var EmailMessage $emailMessage */ + $emailMessage = $this->builder->getTransport(); + + $addresses = $emailMessage->getMessage()->getTo(); + + $emails = []; + /** @var Address $toAddress */ + foreach ($addresses as $address) { + $emails[] = $address->getEmail(); + } + + if (is_string($email)) { + $this->assertCount(1, $emails); + $this->assertEquals($email, $emails[0]); + } else { + $this->assertEquals($email, $emails); + } + } + + /** + * @return array + */ + public function emailDataProvider(): array + { + return [ + [ + 'billy.everything@someserver.com', + ], + [ + [ + 'billy.everything@someserver.com', + 'john.doe@someserver.com', + ] + ] + ]; + } +} From de79f954f25d1189993274529763e528f5ac93f0 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Fri, 4 Oct 2019 14:58:02 -0500 Subject: [PATCH 19/61] MC-21491: Pricing :: FPT display settings - implement schema & resolver --- .../Model/Resolver/StoreConfig.php | 115 ++++++++++++++++++ .../Magento/WeeeGraphQl/etc/schema.graphqls | 14 +++ 2 files changed, 129 insertions(+) create mode 100644 app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php diff --git a/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php new file mode 100644 index 000000000000..49c034185d80 --- /dev/null +++ b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php @@ -0,0 +1,115 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\WeeeGraphQl\Model\Resolver; + +use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; +use Magento\Framework\GraphQl\Config\Element\Field; +use Magento\Framework\GraphQl\Query\ResolverInterface; +use Magento\Weee\Helper\Data; +use Magento\Tax\Helper\Data as TaxHelper; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Weee\Model\Tax as WeeeDisplayConfig; +use Magento\Framework\Pricing\Render; + +class StoreConfig implements ResolverInterface +{ + /** + * @var string + */ + private static $weeeDisplaySettingsNone = 'NONE'; + + /** + * @var array + */ + private static $weeeDisplaySettings = [ + WeeeDisplayConfig::DISPLAY_INCL => 'INCLUDING_FPT', + WeeeDisplayConfig::DISPLAY_INCL_DESCR => 'INCLUDING_FPT_AND_FPT_DESCRIPTION', + WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL => 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', + WeeeDisplayConfig::DISPLAY_EXCL => 'EXCLUDING_FPT' + ]; + + /** + * @var Data + */ + private $weeeHelper; + + /** + * @var TaxHelper + */ + private $taxHelper; + + /** + * @var array + */ + private $computedFptSettings = []; + + /** + * @param Data $weeeHelper + * @param TaxHelper $taxHelper + */ + public function __construct(Data $weeeHelper, TaxHelper $taxHelper) + { + $this->weeeHelper = $weeeHelper; + $this->taxHelper = $taxHelper; + } + + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (empty($this->computedFptSettings)) { + /** @var StoreInterface $store */ + $store = $context->getExtensionAttributes()->getStore(); + $storeId = (int)$store->getId(); + + $this->computedFptSettings = [ + 'product_fixed_product_tax_display_setting' => self::$weeeDisplaySettingsNone, + 'category_fixed_product_tax_display_setting' => self::$weeeDisplaySettingsNone, + 'sales_fixed_product_tax_display_setting' => self::$weeeDisplaySettingsNone, + ]; + if ($this->weeeHelper->isEnabled($store)) { + $productFptDisplay = $this->getWeeDisplaySettingsByZone(Render::ZONE_ITEM_VIEW, $storeId); + $categoryFptDisplay = $this->getWeeDisplaySettingsByZone(Render::ZONE_ITEM_LIST, $storeId); + $salesModulesFptDisplay = $this->getWeeDisplaySettingsByZone(Render::ZONE_SALES, $storeId); + + $this->computedFptSettings = [ + 'product_fixed_product_tax_display_setting' => self::$weeeDisplaySettings[$productFptDisplay] ?? + self::$weeeDisplaySettingsNone, + 'category_fixed_product_tax_display_setting' => self::$weeeDisplaySettings[$categoryFptDisplay] ?? + self::$weeeDisplaySettingsNone, + 'sales_fixed_product_tax_display_setting' => self::$weeeDisplaySettings[$salesModulesFptDisplay] ?? + self::$weeeDisplaySettingsNone, + ]; + } + } + + return $this->computedFptSettings[$info->fieldName] ?? null; + } + + /** + * Get the weee system display setting + * + * @param string $zone + * @param string $storeId + * @return string + */ + private function getWeeDisplaySettingsByZone(string $zone, int $storeId): int + { + return (int) $this->weeeHelper->typeOfDisplay( + null, + $zone, + $storeId + ); + } +} diff --git a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls index 95ca88ee7a99..0d29703289c5 100644 --- a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls @@ -14,3 +14,17 @@ type FixedProductTax @doc(description: "A single FPT that can be applied to a pr amount: Money @doc(description: "Amount of the FPT as a money object.") label: String @doc(description: "The label assigned to the FPT to be displayed on the frontend.") } + +type StoreConfig { + product_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + category_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + sales_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") +} + +enum FixedProductTaxDisplaySettings @doc(description: "This enumeration display settings for the fixed product tax") { + INCLUDING_FPT + INCLUDING_FPT_AND_FPT_DESCRIPTION + EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION + EXCLUDING_FPT + NONE +} From 44fc4c0a3e0b829b8b6d6c7f940249f0bcce3c39 Mon Sep 17 00:00:00 2001 From: Roman Lytvynenko <lytvynen@adobe.com> Date: Fri, 4 Oct 2019 15:39:48 -0500 Subject: [PATCH 20/61] MC-21481: TransportBuilder doesn't add "to" email-addresses, if given in array --- .../TestFramework/Mail/Template/TransportBuilderMock.php | 3 +++ .../Magento/TestFramework/Mail/TransportInterfaceMock.php | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php b/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php index 3f236821b24a..cd9512c22789 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Mail/Template/TransportBuilderMock.php @@ -6,6 +6,9 @@ namespace Magento\TestFramework\Mail\Template; +/** + * Class TransportBuilderMock + */ class TransportBuilderMock extends \Magento\Framework\Mail\Template\TransportBuilder { /** diff --git a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php index 58f031813b48..4cc9533a0e2d 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php @@ -6,10 +6,18 @@ namespace Magento\TestFramework\Mail; +/** + * Class TransportInterfaceMock + */ class TransportInterfaceMock implements \Magento\Framework\Mail\TransportInterface { private $message; + /** + * TransportInterfaceMock constructor. + * + * @param string $message + */ public function __construct($message = '') { $this->message = $message; From 0a308f0a7663d490d8256def18a41e69a63d57fd Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi <vtymchynskyi@magento.com> Date: Fri, 4 Oct 2019 15:52:15 -0500 Subject: [PATCH 21/61] MC-21459: Check/Money Order Language in Admin order view is always from Default Store View --- .../Magento/Payment/Block/InfoTest.php | 56 +++++++++++-------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Payment/Block/InfoTest.php b/dev/tests/integration/testsuite/Magento/Payment/Block/InfoTest.php index 3bd966018b94..ff4f3f8a58bc 100644 --- a/dev/tests/integration/testsuite/Magento/Payment/Block/InfoTest.php +++ b/dev/tests/integration/testsuite/Magento/Payment/Block/InfoTest.php @@ -5,9 +5,24 @@ */ namespace Magento\Payment\Block; +use Magento\Framework\View\Element\Text; +use Magento\Framework\View\LayoutInterface; +use Magento\OfflinePayments\Model\Banktransfer; +use Magento\OfflinePayments\Model\Checkmo; +use Magento\Payment\Block\Info as BlockInfo; +use Magento\Payment\Block\Info\Instructions; +use Magento\Payment\Model\Info; +use Magento\Sales\Model\Order; +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Class InfoTest + */ class InfoTest extends \PHPUnit\Framework\TestCase { /** + * Tests payment info block. + * * @magentoConfigFixture current_store payment/banktransfer/title Bank Method Title * @magentoConfigFixture current_store payment/checkmo/title Checkmo Title Of The Method * @magentoAppArea adminhtml @@ -15,37 +30,32 @@ class InfoTest extends \PHPUnit\Framework\TestCase public function testGetChildPdfAsArray() { /** @var $layout \Magento\Framework\View\Layout */ - $layout = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\View\LayoutInterface::class - ); - $block = $layout->createBlock(\Magento\Payment\Block\Info::class, 'block'); + $layout = Bootstrap::getObjectManager()->get(LayoutInterface::class); + $block = $layout->createBlock(BlockInfo::class, 'block'); - /** @var $paymentInfoBank \Magento\Payment\Model\Info */ - $paymentInfoBank = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Payment\Model\Info::class - ); - $paymentInfoBank->setMethodInstance( - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\OfflinePayments\Model\Banktransfer::class - ) + /** @var $paymentInfoBank Info */ + $paymentInfoBank = Bootstrap::getObjectManager()->create( + Info::class ); - /** @var $childBank \Magento\Payment\Block\Info\Instructions */ - $childBank = $layout->addBlock(\Magento\Payment\Block\Info\Instructions::class, 'child.one', 'block'); + $order = Bootstrap::getObjectManager()->create(Order::class); + $banktransferPayment = Bootstrap::getObjectManager()->create(Banktransfer::class); + $paymentInfoBank->setMethodInstance($banktransferPayment); + $paymentInfoBank->setOrder($order); + /** @var $childBank Instructions */ + $childBank = $layout->addBlock(Instructions::class, 'child.one', 'block'); $childBank->setInfo($paymentInfoBank); $nonExpectedHtml = 'non-expected html'; - $childHtml = $layout->addBlock(\Magento\Framework\View\Element\Text::class, 'child.html', 'block'); + $childHtml = $layout->addBlock(Text::class, 'child.html', 'block'); $childHtml->setText($nonExpectedHtml); - /** @var $paymentInfoCheckmo \Magento\Payment\Model\Info */ - $paymentInfoCheckmo = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Payment\Model\Info::class - ); - $paymentInfoCheckmo->setMethodInstance( - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\OfflinePayments\Model\Checkmo::class - ) + /** @var $paymentInfoCheckmo Info */ + $paymentInfoCheckmo = Bootstrap::getObjectManager()->create( + Info::class ); + $checkmoPayment = Bootstrap::getObjectManager()->create(Checkmo::class); + $paymentInfoCheckmo->setMethodInstance($checkmoPayment); + $paymentInfoCheckmo->setOrder($order); /** @var $childCheckmo \Magento\OfflinePayments\Block\Info\Checkmo */ $childCheckmo = $layout->addBlock( \Magento\OfflinePayments\Block\Info\Checkmo::class, From 379ca7e401387ca487d7a26c733705fde6f386a8 Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Fri, 4 Oct 2019 16:02:48 -0500 Subject: [PATCH 22/61] MC-20456: Category filtering - add api-functional tests --- .../GraphQl/Catalog/CategoryListTest.php | 425 ++++++++++++++++++ .../Magento/Catalog/_files/categories.php | 2 + 2 files changed, 427 insertions(+) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php new file mode 100644 index 000000000000..cbf09ca5d2e6 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php @@ -0,0 +1,425 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Catalog; + +use Magento\TestFramework\TestCase\GraphQlAbstract; + +/** + * Test CategoryList GraphQl query + */ +class CategoryListTest extends GraphQlAbstract +{ + + /** + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + * @dataProvider filterSingleCategoryDataProvider + * @param $field + * @param $condition + * @param $value + */ + public function testFilterSingleCategoryByField($field, $condition, $value, $expectedResult) + { + $query = <<<QUERY +{ + categoryList(filters: { $field : { $condition : "$value" } }){ + id + name + url_key + url_path + children_count + path + position + } +} +QUERY; + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertCount(1, $result['categoryList']); + $this->assertResponseFields($result['categoryList'][0], $expectedResult); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + * @dataProvider filterMultipleCategoriesDataProvider + * @param $field + * @param $condition + * @param $value + * @param $expectedResult + */ + public function testFilterMultipleCategoriesByField($field, $condition, $value, $expectedResult) + { + $query = <<<QUERY +{ + categoryList(filters: { $field : { $condition : $value } }){ + id + name + url_key + url_path + children_count + path + position + } +} +QUERY; + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertCount(count($expectedResult), $result['categoryList']); + foreach ($expectedResult as $i => $expected) { + $this->assertResponseFields($result['categoryList'][$i], $expected); + } + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + */ + public function testFilterCategoryByMultipleFields() + { + $query = <<<QUERY +{ + categoryList(filters: {ids: {in: ["6","7","8","9","10"]}, name: {match: "Movable"}}){ + id + name + url_key + url_path + children_count + path + position + } +} +QUERY; + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertCount(3, $result['categoryList']); + + $expectedCategories = [7 => 'Movable', 9 => 'Movable Position 1', 10 => 'Movable Position 2']; + $actualCategories = array_column($result['categoryList'], 'name', 'id'); + $this->assertEquals($expectedCategories, $actualCategories); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + */ + public function testFilterWithInactiveCategory() + { + $query = <<<QUERY +{ + categoryList(filters: {url_key: {in: ["inactive", "category-2"]}}){ + id + name + url_key + url_path + } +} +QUERY; + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertCount(1, $result['categoryList']); + $actualCategories = array_column($result['categoryList'], 'url_key', 'id'); + $this->assertContains('category-2', $actualCategories); + $this->assertNotContains('inactive', $actualCategories); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + */ + public function testQueryChildCategoriesWithProducts() + { + $query = <<<QUERY +{ + categoryList(filters: {ids: {in: ["3"]}}){ + id + name + url_key + url_path + description + products{ + total_count + items{ + name + sku + } + } + children{ + name + url_key + description + products{ + total_count + items{ + name + sku + } + } + children{ + name + } + } + } +} +QUERY; + + $result = $this->graphQlQuery($query); + $a = 3; + + $this->assertArrayNotHasKey('errors', $result); + $this->assertCount(1, $result['categoryList']); + $baseCategory = $result['categoryList'][0]; + + $this->assertEquals('Category 1', $baseCategory['name']); + $this->assertArrayHasKey('products', $baseCategory); + //Check base category products + $expectedBaseCategoryProducts = [ + ['sku' => 'simple', 'name' => 'Simple Product'], + ['sku' => '12345', 'name' => 'Simple Product Two'], + ['sku' => 'simple-4', 'name' => 'Simple Product Three'] + ]; + $this->assertCategoryProducts($baseCategory, $expectedBaseCategoryProducts); + //Check base category children + $expectedBaseCategoryChildren = [ + ['name' => 'Category 1.1', 'description' => 'Category 1.1 description.'], + ['name' => 'Category 1.2', 'description' => 'Its a description of Test Category 1.2'] + ]; + $this->assertCategoryChildren($baseCategory, $expectedBaseCategoryChildren); + + //Check first child category + $firstChildCategory = $baseCategory['children'][0]; + $this->assertEquals('Category 1.1', $firstChildCategory['name']); + $this->assertEquals('Category 1.1 description.', $firstChildCategory['description']); + $firstChildCategoryExpectedProducts = [ + ['sku' => 'simple', 'name' => 'Simple Product'], + ['sku' => '12345', 'name' => 'Simple Product Two'], + ]; + $this->assertCategoryProducts($firstChildCategory, $firstChildCategoryExpectedProducts); + $firstChildCategoryChildren = [['name' =>'Category 1.1.1']]; + $this->assertCategoryChildren($firstChildCategory, $firstChildCategoryChildren); + //Check second child category + $secondChildCategory = $baseCategory['children'][1]; + $this->assertEquals('Category 1.2', $secondChildCategory['name']); + $this->assertEquals('Its a description of Test Category 1.2', $secondChildCategory['description']); + $firstChildCategoryExpectedProducts = [ + ['sku' => 'simple', 'name' => 'Simple Product'], + ['sku' => 'simple-4', 'name' => 'Simple Product Three'] + ]; + $this->assertCategoryProducts($secondChildCategory, $firstChildCategoryExpectedProducts); + $firstChildCategoryChildren = []; + $this->assertCategoryChildren($secondChildCategory, $firstChildCategoryChildren); + } + + /** + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + */ + public function testNoResultsFound() + { + $query = <<<QUERY +{ + categoryList(filters: {url_key: {in: ["inactive", "does-not-exist"]}}){ + id + name + url_key + url_path + children_count + path + position + } +} +QUERY; + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertArrayHasKey('categoryList', $result); + $this->assertEquals([], $result['categoryList']); + } + + /** + * @return array + */ + public function filterSingleCategoryDataProvider(): array + { + return [ + [ + 'ids', + 'eq', + '4', + [ + 'id' => '4', + 'name' => 'Category 1.1', + 'url_key' => 'category-1-1', + 'url_path' => 'category-1/category-1-1', + 'children_count' => '0', + 'path' => '1/2/3/4', + 'position' => '1' + ] + ], + [ + 'name', + 'match', + 'Movable Position 2', + [ + 'id' => '10', + 'name' => 'Movable Position 2', + 'url_key' => 'movable-position-2', + 'url_path' => 'movable-position-2', + 'children_count' => '0', + 'path' => '1/2/10', + 'position' => '6' + ] + ], + [ + 'url_key', + 'eq', + 'category-1-1-1', + [ + 'id' => '5', + 'name' => 'Category 1.1.1', + 'url_key' => 'category-1-1-1', + 'url_path' => 'category-1/category-1-1/category-1-1-1', + 'children_count' => '0', + 'path' => '1/2/3/4/5', + 'position' => '1' + ] + ], + ]; + } + + /** + * @return array + */ + public function filterMultipleCategoriesDataProvider(): array + { + return[ + //Filter by multiple IDs + [ + 'ids', + 'in', + '["4", "9", "10"]', + [ + [ + 'id' => '4', + 'name' => 'Category 1.1', + 'url_key' => 'category-1-1', + 'url_path' => 'category-1/category-1-1', + 'children_count' => '0', + 'path' => '1/2/3/4', + 'position' => '1' + ], + [ + 'id' => '9', + 'name' => 'Movable Position 1', + 'url_key' => 'movable-position-1', + 'url_path' => 'movable-position-1', + 'children_count' => '0', + 'path' => '1/2/9', + 'position' => '5' + ], + [ + 'id' => '10', + 'name' => 'Movable Position 2', + 'url_key' => 'movable-position-2', + 'url_path' => 'movable-position-2', + 'children_count' => '0', + 'path' => '1/2/10', + 'position' => '6' + ] + ] + ], + //Filter by multiple url keys + [ + 'url_key', + 'in', + '["category-1-2", "movable"]', + [ + [ + 'id' => '7', + 'name' => 'Movable', + 'url_key' => 'movable', + 'url_path' => 'movable', + 'children_count' => '0', + 'path' => '1/2/7', + 'position' => '3' + ], + [ + 'id' => '13', + 'name' => 'Category 1.2', + 'url_key' => 'category-1-2', + 'url_path' => 'category-1/category-1-2', + 'children_count' => '0', + 'path' => '1/2/3/13', + 'position' => '2' + ] + ] + ], + //Filter by matching multiple names + [ + 'name', + 'match', + '"Position"', + [ + [ + 'id' => '9', + 'name' => 'Movable Position 1', + 'url_key' => 'movable-position-1', + 'url_path' => 'movable-position-1', + 'children_count' => '0', + 'path' => '1/2/9', + 'position' => '5' + ], + [ + 'id' => '10', + 'name' => 'Movable Position 2', + 'url_key' => 'movable-position-2', + 'url_path' => 'movable-position-2', + 'children_count' => '0', + 'path' => '1/2/10', + 'position' => '6' + ], + [ + 'id' => '11', + 'name' => 'Movable Position 3', + 'url_key' => 'movable-position-3', + 'url_path' => 'movable-position-3', + 'children_count' => '0', + 'path' => '1/2/11', + 'position' => '7' + ] + ] + ] + ]; + } + + /** + * Check category products + * + * @param array $category + * @param array $expectedProducts + */ + private function assertCategoryProducts(array $category, array $expectedProducts) + { + $this->assertEquals(count($expectedProducts), $category['products']['total_count']); + $this->assertCount(count($expectedProducts), $category['products']['items']); + $this->assertResponseFields($category['products']['items'], $expectedProducts); + } + + /** + * Check category child categories + * + * @param array $category + * @param array $expectedChildren + */ + private function assertCategoryChildren(array $category, array $expectedChildren) + { + $this->assertArrayHasKey('children', $category); + $this->assertCount(count($expectedChildren), $category['children']); + foreach ($expectedChildren as $i => $expectedChild) { + $this->assertResponseFields($category['children'][$i], $expectedChild); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php index a5ab96193246..25bb55ffbc32 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/categories.php @@ -64,6 +64,7 @@ ->setIsActive(true) ->setIsAnchor(true) ->setPosition(1) + ->setDescription('Category 1.1 description.') ->save(); $category = $objectManager->create(\Magento\Catalog\Model\Category::class); @@ -79,6 +80,7 @@ ->setPosition(1) ->setCustomUseParentSettings(0) ->setCustomDesign('Magento/blank') + ->setDescription('This is the description for Category 1.1.1') ->save(); $category = $objectManager->create(\Magento\Catalog\Model\Category::class); From 3a298f658503b9629d903c81ddc1c616990a634f Mon Sep 17 00:00:00 2001 From: Roman Lytvynenko <lytvynen@adobe.com> Date: Fri, 4 Oct 2019 16:14:00 -0500 Subject: [PATCH 23/61] MC-21481: TransportBuilder doesn't add "to" email-addresses, if given in array --- .../Magento/TestFramework/Mail/TransportInterfaceMock.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php index 4cc9533a0e2d..3340608d4a75 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php @@ -30,6 +30,7 @@ public function __construct($message = '') */ public function sendMessage() { + //phpcs:ignore Squiz.PHP.NonExecutableCode.ReturnNotRequired return; } From a505d6dd9a651beffd79bab876e9adedd9a7882d Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Fri, 4 Oct 2019 16:15:02 -0500 Subject: [PATCH 24/61] MC-15986: Category Filtering - add changes in category filter --- .../Model/Category/CategoryFilter.php | 41 +++++++++++++++---- .../Model/Resolver/CategoryList.php | 10 +---- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php index 42f35a871185..8de0d13e51e9 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php +++ b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php @@ -7,7 +7,9 @@ namespace Magento\CatalogGraphQl\Model\Category; +use Magento\Catalog\Api\Data\CategoryInterface; use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; +use Magento\Catalog\Model\ResourceModel\Category\Collection; /** * Category filter allows to filter collection using 'id, url_key, name' from search criteria. @@ -32,24 +34,47 @@ public function __construct( * Filter for filtering the requested categories id's based on url_key, ids, name in the result. * * @param array $args - * @param \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection - * @return bool + * @param Collection $categoryCollection */ public function applyFilters( array $args, - \Magento\Catalog\Model\ResourceModel\Category\Collection $categoryCollection - ): bool { + Collection $categoryCollection + ): void { + $categoryCollection->addAttributeToFilter(CategoryInterface::KEY_IS_ACTIVE, ['eq' => 1]); foreach ($args['filters'] as $field => $cond) { foreach ($cond as $condType => $value) { if ($field === 'ids') { $categoryCollection->addIdFilter($value); - } elseif ($condType === 'match') { - $categoryCollection->addAttributeToFilter($field, ['like' => "%{$value}%"]); } else { - $categoryCollection->addAttributeToFilter($field, [$condType => $value]); + $this->addAttributeFilter($categoryCollection, $field, $condType, $value); } } } - return true; + } + + /** + * @param Collection $categoryCollection + * @param string $field + * @param string $condType + * @param string|array $value + */ + private function addAttributeFilter($categoryCollection, $field, $condType, $value) + { + if ($condType === 'match') { + $this->addMatchFilter($categoryCollection, $field, $value); + return; + } + $categoryCollection->addAttributeToFilter($field, [$condType => $value]); + } + + /** + * + * @param Collection $categoryCollection + * @param string $field + * @param string $value + */ + private function addMatchFilter($categoryCollection, $field, $value) + { + $categoryCollection->addAttributeToFilter($field, ['like' => "%{$value}%"]); } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php index 140cb68be679..5e51791593cb 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php @@ -7,7 +7,6 @@ namespace Magento\CatalogGraphQl\Model\Resolver; -use Magento\Catalog\Model\Category; use Magento\CatalogGraphQl\Model\Resolver\Category\CheckCategoryIsActive; use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ExtractDataFromCategoryTree; use Magento\Framework\GraphQl\Config\Element\Field; @@ -77,10 +76,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value if (isset($value[$field->getName()])) { return $value[$field->getName()]; } - $categoryCollection = $this->collectionFactory->create(); - $categoryCollection->addAttributeToFilter('is_active', 1); - $categoryCollection->addAttributeToSelect(['name','url_key', 'ids']); if (!isset($args['filters'])) { $rootCategoryIds = [(int)$context->getExtensionAttributes()->getStore()->getRootCategoryId()]; @@ -91,14 +87,10 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $rootCategoryIds[] = (int)$category->getId(); } } - $result = []; foreach ($rootCategoryIds as $rootCategoryId) { - if ($rootCategoryId !== Category::TREE_ROOT_ID) { - $this->checkCategoryIsActive->execute($rootCategoryId); - } $categoryTree = $this->categoryTree->getTree($info, $rootCategoryId); - if (empty($categoryTree) || ($categoryTree->count() == 0)) { + if (empty($categoryTree)) { throw new GraphQlNoSuchEntityException(__('Category doesn\'t exist')); } $result[] = current($this->extractDataFromCategoryTree->execute($categoryTree)); From b659839bb3db98050622ccb129728faef7e3e8e4 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Fri, 4 Oct 2019 17:02:17 -0500 Subject: [PATCH 25/61] MC-21491: Pricing :: FPT display settings - modify docs --- app/code/Magento/WeeeGraphQl/etc/schema.graphqls | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls index 0d29703289c5..467b5f701c2f 100644 --- a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls @@ -16,15 +16,15 @@ type FixedProductTax @doc(description: "A single FPT that can be applied to a pr } type StoreConfig { - product_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") - category_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") - sales_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + product_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product page display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + category_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The category page display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + sales_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The sales modules pages display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") } enum FixedProductTaxDisplaySettings @doc(description: "This enumeration display settings for the fixed product tax") { - INCLUDING_FPT - INCLUDING_FPT_AND_FPT_DESCRIPTION - EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION - EXCLUDING_FPT - NONE + INCLUDING_FPT @doc(description: "Fixed product tax amount(s) is included into the price and details from fixed_product_taxes should not be displayed") + INCLUDING_FPT_AND_FPT_DESCRIPTION @doc(description: "Fixed product tax amount(s) is included into the price and the details from fixed_product_taxes should be displayed") + EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION @doc(description: "Fixed product tax amount(s) is included into the price and the details from fixed_product_taxes should be shown, also price without the amount(s) of fixed_product_taxes should be displayed") + EXCLUDING_FPT @doc(description: "Fixed product tax amount(s) is excluded from the price and details from fixed_product_taxes should not be displayed") + NONE @doc(description: "Fixed product tax feature is disabled and we should not show or query fixed_product_taxes field") } From b35c2693366b0841063548ecdeeb43eff9a550fd Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Fri, 4 Oct 2019 17:08:58 -0500 Subject: [PATCH 26/61] MC-21480: Add caching for CategoryList resolver - integration test --- .../Catalog/CategoryListCacheTest.php | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php new file mode 100644 index 000000000000..b91e55267896 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQlCache\Controller\Catalog; + +use Magento\GraphQlCache\Controller\AbstractGraphqlCacheTest; + +/** + * Test caching works for categoryList query + * + * @magentoAppArea graphql + * @magentoCache full_page enabled + * @magentoDbIsolation disabled + */ +class CategoryListCacheTest extends AbstractGraphqlCacheTest +{ + /** + * Test cache tags are generated + * + * @magentoDataFixture Magento/Catalog/_files/category_product.php + */ + public function testRequestCacheTagsForCategoryList(): void + { + $categoryId ='333'; + $query + = <<<QUERY + { + categoryList(filters: {ids: {in: ["$categoryId"]}}) { + id + name + url_key + description + product_count + } + } +QUERY; + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); + $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); + $expectedCacheTags = ['cat_c','cat_c_' . $categoryId, 'FPC']; + $this->assertEquals($expectedCacheTags, $actualCacheTags); + } + + /** + * Test request is served from cache + * + * @magentoDataFixture Magento/Catalog/_files/category_product.php + */ + public function testSecondRequestIsServedFromCache() + { + $categoryId ='333'; + $query + = <<<QUERY + { + categoryList(filters: {ids: {in: ["$categoryId"]}}) { + id + name + url_key + description + product_count + } + } +QUERY; + $expectedCacheTags = ['cat_c','cat_c_' . $categoryId, 'FPC']; + + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); + $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); + $this->assertEquals($expectedCacheTags, $actualCacheTags); + + $cacheResponse = $this->dispatchGraphQlGETRequest(['query' => $query]); + $this->assertEquals('HIT', $cacheResponse->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $actualCacheTags = explode(',', $cacheResponse->getHeader('X-Magento-Tags')->getFieldValue()); + $this->assertEquals($expectedCacheTags, $actualCacheTags); + } +} From e6a42c9d6eb31bd9f48a02d55c02b195e58ef66a Mon Sep 17 00:00:00 2001 From: Roman Lytvynenko <lytvynen@adobe.com> Date: Mon, 7 Oct 2019 11:11:39 -0500 Subject: [PATCH 27/61] MC-21481: TransportBuilder doesn't add "to" email-addresses, if given in array --- .../TestFramework/Mail/TransportInterfaceMock.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php index 3340608d4a75..5bf98b76e7d5 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Mail/TransportInterfaceMock.php @@ -6,19 +6,24 @@ namespace Magento\TestFramework\Mail; +use Magento\Framework\Mail\EmailMessageInterface; + /** * Class TransportInterfaceMock */ class TransportInterfaceMock implements \Magento\Framework\Mail\TransportInterface { + /** + * @var null|EmailMessageInterface + */ private $message; /** * TransportInterfaceMock constructor. * - * @param string $message + * @param null|EmailMessageInterface $message */ - public function __construct($message = '') + public function __construct($message = null) { $this->message = $message; } @@ -37,7 +42,7 @@ public function sendMessage() /** * Get message * - * @return mixed + * @return null|EmailMessageInterface */ public function getMessage() { From 394b70ee71ebd2a789f390ac888d842f0ef3f6bf Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Mon, 7 Oct 2019 13:43:28 -0500 Subject: [PATCH 28/61] MC-20650: Category filtering performance test --- setup/performance-toolkit/benchmark.jmx | 205 ++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index 00ae0bdbb8a4..ddc52133d75d 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -39431,6 +39431,64 @@ if (name == null) { Failure = false; } } +</stringProp> + <stringProp name="BeanShellAssertion.filename"/> + <stringProp name="BeanShellAssertion.parameters"/> + <boolProp name="BeanShellAssertion.resetInterpreter">false</boolProp> + </BeanShellAssertion> + <hashTree/> + </hashTree> + + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Query CategoryList" enabled="true"> + <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> + <collectionProp name="Arguments.arguments"> + <elementProp name="" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">false</boolProp> + <stringProp name="Argument.value">{"query":"{\n categoryList{\n name\n id\n level\n description\n path\n path_in_store\n url_key\n url_path\n children {\n id\n description\n default_sort_by\n children {\n id\n description\n level\n children {\n level\n id\n children {\n id\n }\n }\n }\n }\n }\n}","variables":null,"operationName":null}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port"/> + <stringProp name="HTTPSampler.connect_timeout"/> + <stringProp name="HTTPSampler.response_timeout"/> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}graphql</stringProp> + <stringProp name="HTTPSampler.method">POST</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/graphql/query_root_category_list.jmx</stringProp> + </HTTPSamplerProxy> + <hashTree> + <com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor guiclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.gui.JSONPathExtractorGui" testclass="com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor" testname="Extract total_count" enabled="true"> + <stringProp name="VAR">graphql_categoryList_query_name</stringProp> + <stringProp name="JSONPATH">$.data.categoryList[0].name</stringProp> + <stringProp name="DEFAULT"/> + <stringProp name="VARIABLE"/> + <stringProp name="SUBJECT">BODY</stringProp> + <stringProp name="INPUT_FORMAT">JSON</stringProp> + </com.atlantbh.jmeter.plugins.jsonutils.jsonpathextractor.JSONPathExtractor> + <hashTree/> + <BeanShellAssertion guiclass="BeanShellAssertionGui" testclass="BeanShellAssertion" testname="BeanShell Assertion" enabled="true"> + <stringProp name="BeanShellAssertion.query">String name = vars.get("graphql_categoryList_query_name"); +if (name == null) { + Failure = true; + FailureMessage = "Not Expected \"children\" to be null"; +} else { + if (!name.equals("Default Category")) { + Failure = true; + FailureMessage = "Expected \"name\" to equal \"Default Category\", Actual: " + name; + } else { + Failure = false; + } +} </stringProp> <stringProp name="BeanShellAssertion.filename"/> <stringProp name="BeanShellAssertion.parameters"/> @@ -40361,6 +40419,153 @@ function assertCategoryChildren(category, response) { } +</stringProp> + </JSR223Assertion> + <hashTree/> + </hashTree> + </hashTree> + + + <ThroughputController guiclass="ThroughputControllerGui" testclass="ThroughputController" testname="GraphQL Get Category List by category_url_key" enabled="true"> + <intProp name="ThroughputController.style">1</intProp> + <boolProp name="ThroughputController.perThread">false</boolProp> + <intProp name="ThroughputController.maxThroughput">1</intProp> + <stringProp name="ThroughputController.percentThroughput">${graphqlGetCategoryListByCategoryIdPercentage}</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/_system/scenario_controller_tmpl.jmx</stringProp></ThroughputController> + <hashTree> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Set Test Label" enabled="true"> + <stringProp name="script"> +var testLabel = "${testLabel}" ? " (${testLabel})" : ""; +if (testLabel + && sampler.getClass().getName() == 'org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy' +) { + if (sampler.getName().indexOf(testLabel) == -1) { + sampler.setName(sampler.getName() + testLabel); + } +} else if (sampler.getName().indexOf("SetUp - ") == -1) { + sampler.setName("SetUp - " + sampler.getName()); +} + </stringProp> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/_system/setup_label.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - Set Label" enabled="true"> + <stringProp name="BeanShellSampler.query"> + vars.put("testLabel", "GraphQL Get Category List by category_url_key"); + </stringProp> + <boolProp name="BeanShellSampler.resetInterpreter">true</boolProp> + </BeanShellSampler> + <hashTree/> + + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Content-Type</stringProp> + <stringProp name="Header.value">application/json</stringProp> + </elementProp> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Accept</stringProp> + <stringProp name="Header.value">*/*</stringProp> + </elementProp> + </collectionProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/api/header_manager_before_token.jmx</stringProp></HeaderManager> + <hashTree/> + + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - Init Random Generator" enabled="true"> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/init_random_generator_setup.jmx</stringProp> + <stringProp name="BeanShellSampler.query"> +import java.util.Random; + +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom} + ${__threadNum}); +} + +vars.putObject("randomIntGenerator", random); + </stringProp> + <stringProp name="BeanShellSampler.filename"/> + <stringProp name="BeanShellSampler.parameters"/> + <boolProp name="BeanShellSampler.resetInterpreter">true</boolProp> + </BeanShellSampler> + <hashTree/> + + <JSR223Sampler guiclass="TestBeanGUI" testclass="JSR223Sampler" testname="SetUp - Prepare Category Data" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script">random = vars.getObject("randomIntGenerator"); + +var categories = props.get("categories"); +number = random.nextInt(categories.length); + +vars.put("category_url_key", categories[number].url_key); +vars.put("category_name", categories[number].name); +vars.put("category_id", categories[number].id); +vars.putObject("category", categories[number]); + </stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/extract_category_setup.jmx</stringProp></JSR223Sampler> + <hashTree/> + + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Get Category List by category_url_key" enabled="true"> + <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> + <collectionProp name="Arguments.arguments"> + <elementProp name="" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">false</boolProp> + <stringProp name="Argument.value">{"query" : "{\n categoryList(filters:{url_key: {in: [\"${category_url_key}\"]}}) {\n id\n children {\n id\n name\n url_key\n url_path\n children_count\n path\n image\n productImagePreview: products(pageSize: 1, sort: {name: ASC}) {\n items {\n small_image {\n label\n url\n }\n }\n }\n }\n }\n}"}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port">${graphql_port_number}</stringProp> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}graphql</stringProp> + <stringProp name="HTTPSampler.method">POST</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/graphql/get_category_list_by_category_url_key.jmx</stringProp> + </HTTPSamplerProxy> + <hashTree> + <JSR223Assertion guiclass="TestBeanGUI" testclass="JSR223Assertion" testname="Assert found categories" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script">var category = vars.getObject("category"); +var response = JSON.parse(prev.getResponseDataAsString()); + +assertCategoryId(category, response); +assertCategoryChildren(category, response); + +function assertCategoryId(category, response) { + if (response.data == undefined || response.data.categoryList == undefined || response.data.categoryList[0].id != category.id) { + AssertionResult.setFailureMessage("Cannot find category with id \"" + category.id + "\""); + AssertionResult.setFailure(true); + } +} + +function assertCategoryChildren(category, response) { + foundCategory = response.data && response.data.categoryList ? response.data.categoryList[0] : null; + if (foundCategory) { + var childrenFound = foundCategory.children.map(function (c) {return parseInt(c.id)}); + var children = category.children.map(function (c) {return parseInt(c)}); + if (JSON.stringify(children.sort()) != JSON.stringify(childrenFound.sort())) { + AssertionResult.setFailureMessage("Cannot math children categories \"" + JSON.stringify(children) + "\" for to found one: \"" + JSON.stringify(childrenFound) + "\""); + AssertionResult.setFailure(true); + } + } + +} + </stringProp> </JSR223Assertion> <hashTree/> From 44c6a2f2f94e233db48996ef90bc578664eea04f Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 7 Oct 2019 14:53:10 -0500 Subject: [PATCH 29/61] MC-21491: Pricing :: FPT display settings - implement tests - moved FPT tests from catalog to Weee folder --- .../GraphQl/Weee/ProductPriceWithFPTTest.php | 203 ++++++++++++++++++ .../StoreConfigFPTTest.php} | 2 +- 2 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php rename dev/tests/api-functional/testsuite/Magento/GraphQl/{Catalog/ProductPriceWithFPTTest.php => Weee/StoreConfigFPTTest.php} (99%) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php new file mode 100644 index 000000000000..b4427f2e3247 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php @@ -0,0 +1,203 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\GraphQl\Weee; + +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\Config\Storage\WriterInterface; +use Magento\Framework\ObjectManager\ObjectManager; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\GraphQlAbstract; +use Magento\Weee\Model\Tax as WeeeDisplayConfig; +use Magento\Weee\Model\Config; + +/** + * Test for storeConfig FPT config values + * + * @SuppressWarnings(PHPMD.TooManyPublicMethods) + */ +class StoreConfigFPTTest extends GraphQlAbstract +{ + /** @var ObjectManager $objectManager */ + private $objectManager; + + /** + * @inheritdoc + */ + protected function setUp() :void + { + $this->objectManager = Bootstrap::getObjectManager(); + } + + /** + * FPT All Display settings + * + * @param array $weeTaxSettings + * @param string $displayValue + * @return void + * + * @dataProvider sameFPTDisplaySettingsProvider + */ + public function testSameFPTDisplaySettings(array $weeTaxSettings, $displayValue) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + $query = $this->getStoreConfigQuery(); + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + + $this->assertNotEmpty($result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['category_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['sales_fixed_product_tax_display_setting']); + + $this->assertEquals($displayValue, $result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertEquals($displayValue, $result['storeConfig']['category_fixed_product_tax_display_setting']); + $this->assertEquals($displayValue, $result['storeConfig']['sales_fixed_product_tax_display_setting']); + } + + /** + * SameFPTDisplaySettings settings data provider + * + * @return array + */ + public function sameFPTDisplaySettingsProvider() + { + return [ + [ + 'weeTaxSettingsDisplayIncludedOnly' => [ + 'tax/weee/enable' => '1', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL, + ], + 'displayValue' => 'INCLUDING_FPT', + ], + [ + 'weeTaxSettingsDisplayIncludedAndDescription' => [ + 'tax/weee/enable' => '1', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + ], + 'displayValue' => 'INCLUDING_FPT_AND_FPT_DESCRIPTION', + ], + [ + 'weeTaxSettingsDisplayIncludedAndExcludedAndDescription' => [ + 'tax/weee/enable' => '1', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + ], + 'displayValue' => 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', + ], + [ + 'weeTaxSettingsDisplayExcluded' => [ + 'tax/weee/enable' => '1', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, + ], + 'displayValue' => 'EXCLUDING_FPT', + ], + [ + 'weeTaxSettingsDisplayExcluded' => [ + 'tax/weee/enable' => '0', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, + ], + 'displayValue' => 'NONE', + ], + ]; + } + + /** + * FPT Display setting shuffled + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider differentFPTDisplaySettingsProvider + */ + public function testDifferentFPTDisplaySettings(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + $query = $this->getStoreConfigQuery(); + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + + $this->assertNotEmpty($result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['category_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['sales_fixed_product_tax_display_setting']); + + $this->assertEquals('INCLUDING_FPT', $result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertEquals( + 'INCLUDING_FPT_AND_FPT_DESCRIPTION', + $result['storeConfig']['category_fixed_product_tax_display_setting'] + ); + $this->assertEquals( + 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', + $result['storeConfig']['sales_fixed_product_tax_display_setting'] + ); + } + + /** + * DifferentFPTDisplaySettings settings data provider + * + * @return array + */ + public function differentFPTDisplaySettingsProvider() + { + return [ + [ + 'weeTaxSettingsDisplay' => [ + 'tax/weee/enable' => '1', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + ] + ], + ]; + } + + /** + * Get GraphQl query to fetch storeConfig and FPT serttings + * + * @return string + */ + private function getStoreConfigQuery(): string + { + return <<<QUERY +{ + storeConfig { + product_fixed_product_tax_display_setting + category_fixed_product_tax_display_setting + sales_fixed_product_tax_display_setting + } +} +QUERY; + } +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php similarity index 99% rename from dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductPriceWithFPTTest.php rename to dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php index 69308b38cbf7..6bf851287458 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/ProductPriceWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php @@ -5,7 +5,7 @@ */ declare(strict_types=1); -namespace Magento\GraphQl\Catalog; +namespace Magento\GraphQl\Weee; use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Product; From 161b70644c6f432832dae01715e64e78ebe6e847 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 7 Oct 2019 14:56:46 -0500 Subject: [PATCH 30/61] MC-21491: Pricing :: FPT display settings - switch names for tests --- .../GraphQl/Weee/ProductPriceWithFPTTest.php | 651 +++++++++++++++--- .../GraphQl/Weee/StoreConfigFPTTest.php | 651 +++--------------- 2 files changed, 651 insertions(+), 651 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php index b4427f2e3247..6bf851287458 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php @@ -7,20 +7,22 @@ namespace Magento\GraphQl\Weee; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Config\Storage\WriterInterface; use Magento\Framework\ObjectManager\ObjectManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; -use Magento\Weee\Model\Tax as WeeeDisplayConfig; -use Magento\Weee\Model\Config; +use Magento\Tax\Model\ClassModel as TaxClassModel; +use Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory as TaxClassCollectionFactory; /** - * Test for storeConfig FPT config values + * Test for Product Price With FPT * * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ -class StoreConfigFPTTest extends GraphQlAbstract +class ProductPriceWithFPTTest extends GraphQlAbstract { /** @var ObjectManager $objectManager */ private $objectManager; @@ -34,15 +36,18 @@ protected function setUp() :void } /** - * FPT All Display settings + * Catalog Prices : Excluding Tax + * Catalog Display setting: Excluding Tax + * FPT Display setting: Including FPT only * * @param array $weeTaxSettings - * @param string $displayValue * @return void * - * @dataProvider sameFPTDisplaySettingsProvider + * @dataProvider catalogPriceExcludeTaxAndIncludeFPTOnlySettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php */ - public function testSameFPTDisplaySettings(array $weeTaxSettings, $displayValue) + public function testCatalogPriceExcludeTaxAndIncludeFPTOnly(array $weeTaxSettings) { /** @var WriterInterface $configWriter */ $configWriter = $this->objectManager->get(WriterInterface::class); @@ -55,85 +60,415 @@ public function testSameFPTDisplaySettings(array $weeTaxSettings, $displayValue) $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); $scopeConfig->clean(); - $query = $this->getStoreConfigQuery(); + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + + // final price and regular price are the sum of product price and FPT + $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); - $this->assertNotEmpty($result['storeConfig']['product_fixed_product_tax_display_setting']); - $this->assertNotEmpty($result['storeConfig']['category_fixed_product_tax_display_setting']); - $this->assertNotEmpty($result['storeConfig']['sales_fixed_product_tax_display_setting']); + $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); - $this->assertEquals($displayValue, $result['storeConfig']['product_fixed_product_tax_display_setting']); - $this->assertEquals($displayValue, $result['storeConfig']['category_fixed_product_tax_display_setting']); - $this->assertEquals($displayValue, $result['storeConfig']['sales_fixed_product_tax_display_setting']); + $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); + $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; + $this->assertEquals(12.7, $fixedProductTax['amount']['value']); + $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); } /** - * SameFPTDisplaySettings settings data provider + * CatalogPriceExcludeTaxAndIncludeFPTOnlyProvider settings data provider * * @return array */ - public function sameFPTDisplaySettingsProvider() + public function catalogPriceExcludeTaxAndIncludeFPTOnlySettingsProvider() { return [ [ - 'weeTaxSettingsDisplayIncludedOnly' => [ + 'weeTaxSettings' => [ + 'tax/display/type' => '1', 'tax/weee/enable' => '1', - Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL, - Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL, - Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL, - ], - 'displayValue' => 'INCLUDING_FPT', - ], + 'tax/weee/display' => '0', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '0', + ] + ] + ]; + } + + /** + * Catalog Prices : Excluding Tax + * Catalog Display setting: Excluding Tax + * FPT Display setting: Including FPT and FPT description + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider catalogPriceExcludeTaxAndIncludeFPTWithDescriptionSettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + */ + public function testCatalogPriceExcludeTaxAndIncludeFPTWithDescription(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + + // final price and regular price are the sum of product price and FPT + $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); + + $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); + + $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); + $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; + $this->assertEquals(12.7, $fixedProductTax['amount']['value']); + $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); + } + + /** + * CatalogPriceExcludeTaxAndIncludeFPTWithDescription settings data provider + * + * @return array + */ + public function catalogPriceExcludeTaxAndIncludeFPTWithDescriptionSettingsProvider() + { + return [ [ - 'weeTaxSettingsDisplayIncludedAndDescription' => [ + 'weeTaxSettings' => [ + 'tax/display/type' => '1', 'tax/weee/enable' => '1', - Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL_DESCR, - Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL_DESCR, - Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL_DESCR, - ], - 'displayValue' => 'INCLUDING_FPT_AND_FPT_DESCRIPTION', - ], + 'tax/weee/display' => '1', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '0', + ] + ] + ]; + } + + /** + * Catalog Prices : Excluding Tax + * Catalog Display setting: Including Tax + * FPT Display setting: Including FPT only + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider catalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnlySettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + */ + public function testCatalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnly(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ + $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); + $taxClassCollection = $taxClassCollectionFactory->create(); + /** @var TaxClassModel $taxClass */ + $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); + $taxClass = $taxClassCollection->getFirstItem(); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + /** @var Product $prod2 */ + $product1 = $productRepository->get('simple-with-ftp'); + $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); + $productRepository->save($product1); + + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); + + // final price and regular price are the sum of product price, FPT and product tax + $this->assertEquals(120.2, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); + $this->assertEquals(120.2, round($product['price_range']['minimum_price']['final_price']['value'], 2)); + + $this->assertEquals(120.2, round($product['price_range']['maximum_price']['regular_price']['value'], 2)); + $this->assertEquals(120.2, round($product['price_range']['maximum_price']['final_price']['value'], 2)); + } + + /** + * CatalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnly settings data provider + * + * @return array + */ + public function catalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnlySettingsProvider() + { + return [ [ - 'weeTaxSettingsDisplayIncludedAndExcludedAndDescription' => [ + 'weeTaxSettings' => [ + 'tax/calculation/price_includes_tax' => '0', + 'tax/display/type' => '2', 'tax/weee/enable' => '1', - Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, - Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, - Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, - ], - 'displayValue' => 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', - ], + 'tax/weee/display' => '0', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '0', + ] + ] + ]; + } + + /** + * Catalog Prices : Excluding Tax + * Catalog Display setting: Including Tax + * FPT Display setting: Including FPT and FPT description + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider catalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescriptionSettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + */ + public function testCatalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescription(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ + $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); + $taxClassCollection = $taxClassCollectionFactory->create(); + /** @var TaxClassModel $taxClass */ + $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); + $taxClass = $taxClassCollection->getFirstItem(); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + /** @var Product $product1 */ + $product1 = $productRepository->get('simple-with-ftp'); + $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); + $productRepository->save($product1); + + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + + $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); + // final price and regular price are the sum of product price and FPT + $this->assertEquals(120.2, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); + $this->assertEquals(120.2, round($product['price_range']['minimum_price']['final_price']['value'], 2)); + + $this->assertEquals(120.2, round($product['price_range']['maximum_price']['regular_price']['value'], 2)); + $this->assertEquals(120.2, round($product['price_range']['maximum_price']['final_price']['value'], 2)); + } + + /** + * CatalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescription settings data provider + * + * @return array + */ + public function catalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescriptionSettingsProvider() + { + return [ [ - 'weeTaxSettingsDisplayExcluded' => [ + 'weeTaxSettings' => [ + 'tax/calculation/price_includes_tax' => '0', + 'tax/display/type' => '2', 'tax/weee/enable' => '1', - Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL, - Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, - Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, - ], - 'displayValue' => 'EXCLUDING_FPT', - ], + 'tax/weee/display' => '1', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '0', + ] + ] + ]; + } + + /** + * Catalog Prices : Including Tax + * Catalog Display setting: Excluding Tax + * FPT Display setting: Including FPT and FPT description + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider catalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescriptionSettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + */ + public function testCatalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescription(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + + // final price and regular price are the sum of product price and FPT + $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); + + $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); + + $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); + $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; + $this->assertEquals(12.7, $fixedProductTax['amount']['value']); + $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); + } + + /** + * CatalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescription settings data provider + * + * @return array + */ + public function catalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescriptionSettingsProvider() + { + return [ [ - 'weeTaxSettingsDisplayExcluded' => [ - 'tax/weee/enable' => '0', - Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL, - Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, - Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, - ], - 'displayValue' => 'NONE', - ], + 'weeTaxSettings' => [ + 'tax/calculation/price_includes_tax' => '1', + 'tax/display/type' => '1', + 'tax/weee/enable' => '1', + 'tax/weee/display' => '1', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '1', + ] + ] ]; } /** - * FPT Display setting shuffled + * Catalog Prices : Including Tax + * Catalog Display setting: Including Tax + * FPT Display setting: Including FPT Only * * @param array $weeTaxSettings * @return void * - * @dataProvider differentFPTDisplaySettingsProvider + * @dataProvider catalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnlySettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + */ + public function testCatalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnly(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + + // final price and regular price are the sum of product price and FPT + $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); + + $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); + $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); + + $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); + $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; + $this->assertEquals(12.7, $fixedProductTax['amount']['value']); + $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); + } + + /** + * CatalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnly settings data provider + * + * @return array */ - public function testDifferentFPTDisplaySettings(array $weeTaxSettings) + public function catalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnlySettingsProvider() { + return [ + [ + 'weeTaxSettings' => [ + 'tax/calculation/price_includes_tax' => '1', + 'tax/display/type' => '2', + 'tax/weee/enable' => '1', + 'tax/weee/display' => '0', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '0', + ] + ] + ]; + } + + /** + * Catalog Prices : Including Tax + * Catalog Display setting: Including Tax + * FPT Display setting: Including FPT and FPT Description + * Apply Tax to FPT = Yes + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider catalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPTSettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + */ + public function testCatalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPT( + array $weeTaxSettings + ) { /** @var WriterInterface $configWriter */ $configWriter = $this->objectManager->get(WriterInterface::class); @@ -144,59 +479,215 @@ public function testDifferentFPTDisplaySettings(array $weeTaxSettings) /** @var ScopeConfigInterface $scopeConfig */ $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); $scopeConfig->clean(); + /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ + $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); + $taxClassCollection = $taxClassCollectionFactory->create(); + /** @var TaxClassModel $taxClass */ + $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); + $taxClass = $taxClassCollection->getFirstItem(); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + /** @var Product $product1 */ + $product1 = $productRepository->get('simple-with-ftp'); + $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); + $productRepository->save($product1); - $query = $this->getStoreConfigQuery(); + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + + //12.7 + 7.5% of 12.7 = 13.65 + $fptWithTax = round(13.65, 2); + // final price and regular price are the sum of product price and FPT + $this->assertEquals(113.65, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); + $this->assertEquals(113.65, round($product['price_range']['minimum_price']['final_price']['value'], 2)); + + $this->assertEquals(113.65, round($product['price_range']['maximum_price']['regular_price']['value'], 2)); + $this->assertEquals(113.65, round($product['price_range']['maximum_price']['final_price']['value'], 2)); + + $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); + $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; + $this->assertEquals($fptWithTax, round($fixedProductTax['amount']['value'], 2)); + $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); + } + + /** + * CatalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPT settings data provider + * + * @return array + */ + public function catalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPTSettingsProvider() + { + return [ + [ + 'weeTaxSettings' => [ + 'tax/calculation/price_includes_tax' > '1', + 'tax/display/type' => '2', + 'tax/weee/enable' => '1', + 'tax/weee/display' => '0', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '1', + ] + ] + ]; + } - $this->assertNotEmpty($result['storeConfig']['product_fixed_product_tax_display_setting']); - $this->assertNotEmpty($result['storeConfig']['category_fixed_product_tax_display_setting']); - $this->assertNotEmpty($result['storeConfig']['sales_fixed_product_tax_display_setting']); + /** + * Use multiple FPTs per product with the below tax/fpt configurations + * + * Catalog Prices : Including Tax + * Catalog Display setting: Including Tax + * FPT Display setting: Including FPT and FPT description + * Apply tax on FPT : Yes + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider catalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + * @magentoApiDataFixture Magento/Weee/_files/fixed_product_attribute.php + * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + */ + public function testCatalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTs(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); - $this->assertEquals('INCLUDING_FPT', $result['storeConfig']['product_fixed_product_tax_display_setting']); - $this->assertEquals( - 'INCLUDING_FPT_AND_FPT_DESCRIPTION', - $result['storeConfig']['category_fixed_product_tax_display_setting'] + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ + $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); + $taxClassCollection = $taxClassCollectionFactory->create(); + /** @var TaxClassModel $taxClass */ + $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); + $taxClass = $taxClassCollection->getFirstItem(); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + /** @var Product $product1 */ + $product1 = $productRepository->get('simple-with-ftp'); + $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); + $product1->setFixedProductAttribute( + [['website_id' => 0, 'country' => 'US', 'state' => 0, 'price' => 10, 'delete' => '']] + ); + $productRepository->save($product1); + + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + $this->assertEquals(124.40, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); + $this->assertCount( + 2, + $product['price_range']['minimum_price']['fixed_product_taxes'], + 'Fixed product tax count is incorrect' ); - $this->assertEquals( - 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', - $result['storeConfig']['sales_fixed_product_tax_display_setting'] + $this->assertResponseFields( + $product['price_range']['minimum_price']['fixed_product_taxes'], + [ + [ + 'amount' => [ + 'value' => 13.6525 + ], + 'label' => 'fpt_for_all_front_label' + ], + [ + 'amount' => [ + 'value' => 10.75 + ], + 'label' => 'fixed_product_attribute_front_label' + ], + ] ); } /** - * DifferentFPTDisplaySettings settings data provider + * CatalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSettingsProvider settings data provider * * @return array */ - public function differentFPTDisplaySettingsProvider() + public function catalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSettingsProvider() { return [ [ - 'weeTaxSettingsDisplay' => [ + 'weeTaxSettings' => [ + 'tax/calculation/price_includes_tax' => '1', + 'tax/display/type' => '2', 'tax/weee/enable' => '1', - Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL, - Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL_DESCR, - Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + 'tax/weee/display' => '1', + 'tax/defaults/region' => '1', + 'tax/weee/apply_vat' => '1', ] - ], + ] ]; } /** - * Get GraphQl query to fetch storeConfig and FPT serttings + * Get GraphQl query to fetch products by sku * + * @param array $skus * @return string */ - private function getStoreConfigQuery(): string + private function getProductQuery(array $skus): string { + $stringSkus = '"' . implode('","', $skus) . '"'; return <<<QUERY { - storeConfig { - product_fixed_product_tax_display_setting - category_fixed_product_tax_display_setting - sales_fixed_product_tax_display_setting + products(filter: {sku: {in: [$stringSkus]}}, sort: {name: ASC}) { + items { + name + sku + price_range { + minimum_price { + regular_price { + value + currency + } + final_price { + value + currency + } + discount { + amount_off + percent_off + } + fixed_product_taxes{ + amount{value} + label + } + } + maximum_price { + regular_price { + value + currency + } + final_price { + value + currency + } + discount { + amount_off + percent_off + } + fixed_product_taxes + { + amount{value} + label + } + } + } } + } } QUERY; } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php index 6bf851287458..b4427f2e3247 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php @@ -7,22 +7,20 @@ namespace Magento\GraphQl\Weee; -use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Catalog\Model\Product; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Config\Storage\WriterInterface; use Magento\Framework\ObjectManager\ObjectManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; -use Magento\Tax\Model\ClassModel as TaxClassModel; -use Magento\Tax\Model\ResourceModel\TaxClass\CollectionFactory as TaxClassCollectionFactory; +use Magento\Weee\Model\Tax as WeeeDisplayConfig; +use Magento\Weee\Model\Config; /** - * Test for Product Price With FPT + * Test for storeConfig FPT config values * * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ -class ProductPriceWithFPTTest extends GraphQlAbstract +class StoreConfigFPTTest extends GraphQlAbstract { /** @var ObjectManager $objectManager */ private $objectManager; @@ -36,18 +34,15 @@ protected function setUp() :void } /** - * Catalog Prices : Excluding Tax - * Catalog Display setting: Excluding Tax - * FPT Display setting: Including FPT only + * FPT All Display settings * * @param array $weeTaxSettings + * @param string $displayValue * @return void * - * @dataProvider catalogPriceExcludeTaxAndIncludeFPTOnlySettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php + * @dataProvider sameFPTDisplaySettingsProvider */ - public function testCatalogPriceExcludeTaxAndIncludeFPTOnly(array $weeTaxSettings) + public function testSameFPTDisplaySettings(array $weeTaxSettings, $displayValue) { /** @var WriterInterface $configWriter */ $configWriter = $this->objectManager->get(WriterInterface::class); @@ -60,415 +55,85 @@ public function testCatalogPriceExcludeTaxAndIncludeFPTOnly(array $weeTaxSetting $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); $scopeConfig->clean(); - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); - + $query = $this->getStoreConfigQuery(); $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - - // final price and regular price are the sum of product price and FPT - $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); - $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); + $this->assertNotEmpty($result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['category_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['sales_fixed_product_tax_display_setting']); - $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); - $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; - $this->assertEquals(12.7, $fixedProductTax['amount']['value']); - $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); + $this->assertEquals($displayValue, $result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertEquals($displayValue, $result['storeConfig']['category_fixed_product_tax_display_setting']); + $this->assertEquals($displayValue, $result['storeConfig']['sales_fixed_product_tax_display_setting']); } /** - * CatalogPriceExcludeTaxAndIncludeFPTOnlyProvider settings data provider + * SameFPTDisplaySettings settings data provider * * @return array */ - public function catalogPriceExcludeTaxAndIncludeFPTOnlySettingsProvider() + public function sameFPTDisplaySettingsProvider() { return [ [ - 'weeTaxSettings' => [ - 'tax/display/type' => '1', + 'weeTaxSettingsDisplayIncludedOnly' => [ 'tax/weee/enable' => '1', - 'tax/weee/display' => '0', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '0', - ] - ] - ]; - } - - /** - * Catalog Prices : Excluding Tax - * Catalog Display setting: Excluding Tax - * FPT Display setting: Including FPT and FPT description - * - * @param array $weeTaxSettings - * @return void - * - * @dataProvider catalogPriceExcludeTaxAndIncludeFPTWithDescriptionSettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php - */ - public function testCatalogPriceExcludeTaxAndIncludeFPTWithDescription(array $weeTaxSettings) - { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); - - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); - - $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - - // final price and regular price are the sum of product price and FPT - $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); - - $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); - - $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); - $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; - $this->assertEquals(12.7, $fixedProductTax['amount']['value']); - $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); - } - - /** - * CatalogPriceExcludeTaxAndIncludeFPTWithDescription settings data provider - * - * @return array - */ - public function catalogPriceExcludeTaxAndIncludeFPTWithDescriptionSettingsProvider() - { - return [ + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL, + ], + 'displayValue' => 'INCLUDING_FPT', + ], [ - 'weeTaxSettings' => [ - 'tax/display/type' => '1', + 'weeTaxSettingsDisplayIncludedAndDescription' => [ 'tax/weee/enable' => '1', - 'tax/weee/display' => '1', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '0', - ] - ] - ]; - } - - /** - * Catalog Prices : Excluding Tax - * Catalog Display setting: Including Tax - * FPT Display setting: Including FPT only - * - * @param array $weeTaxSettings - * @return void - * - * @dataProvider catalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnlySettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php - */ - public function testCatalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnly(array $weeTaxSettings) - { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); - - /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ - $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); - $taxClassCollection = $taxClassCollectionFactory->create(); - /** @var TaxClassModel $taxClass */ - $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); - $taxClass = $taxClassCollection->getFirstItem(); - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); - /** @var Product $prod2 */ - $product1 = $productRepository->get('simple-with-ftp'); - $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); - $productRepository->save($product1); - - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); - - $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); - - // final price and regular price are the sum of product price, FPT and product tax - $this->assertEquals(120.2, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); - $this->assertEquals(120.2, round($product['price_range']['minimum_price']['final_price']['value'], 2)); - - $this->assertEquals(120.2, round($product['price_range']['maximum_price']['regular_price']['value'], 2)); - $this->assertEquals(120.2, round($product['price_range']['maximum_price']['final_price']['value'], 2)); - } - - /** - * CatalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnly settings data provider - * - * @return array - */ - public function catalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnlySettingsProvider() - { - return [ + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + ], + 'displayValue' => 'INCLUDING_FPT_AND_FPT_DESCRIPTION', + ], [ - 'weeTaxSettings' => [ - 'tax/calculation/price_includes_tax' => '0', - 'tax/display/type' => '2', + 'weeTaxSettingsDisplayIncludedAndExcludedAndDescription' => [ 'tax/weee/enable' => '1', - 'tax/weee/display' => '0', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '0', - ] - ] - ]; - } - - /** - * Catalog Prices : Excluding Tax - * Catalog Display setting: Including Tax - * FPT Display setting: Including FPT and FPT description - * - * @param array $weeTaxSettings - * @return void - * - * @dataProvider catalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescriptionSettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php - */ - public function testCatalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescription(array $weeTaxSettings) - { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); - - /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ - $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); - $taxClassCollection = $taxClassCollectionFactory->create(); - /** @var TaxClassModel $taxClass */ - $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); - $taxClass = $taxClassCollection->getFirstItem(); - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); - /** @var Product $product1 */ - $product1 = $productRepository->get('simple-with-ftp'); - $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); - $productRepository->save($product1); - - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); - - $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - - $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); - // final price and regular price are the sum of product price and FPT - $this->assertEquals(120.2, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); - $this->assertEquals(120.2, round($product['price_range']['minimum_price']['final_price']['value'], 2)); - - $this->assertEquals(120.2, round($product['price_range']['maximum_price']['regular_price']['value'], 2)); - $this->assertEquals(120.2, round($product['price_range']['maximum_price']['final_price']['value'], 2)); - } - - /** - * CatalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescription settings data provider - * - * @return array - */ - public function catalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescriptionSettingsProvider() - { - return [ + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, + ], + 'displayValue' => 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', + ], [ - 'weeTaxSettings' => [ - 'tax/calculation/price_includes_tax' => '0', - 'tax/display/type' => '2', + 'weeTaxSettingsDisplayExcluded' => [ 'tax/weee/enable' => '1', - 'tax/weee/display' => '1', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '0', - ] - ] - ]; - } - - /** - * Catalog Prices : Including Tax - * Catalog Display setting: Excluding Tax - * FPT Display setting: Including FPT and FPT description - * - * @param array $weeTaxSettings - * @return void - * - * @dataProvider catalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescriptionSettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php - */ - public function testCatalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescription(array $weeTaxSettings) - { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); - - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); - - $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - - // final price and regular price are the sum of product price and FPT - $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); - - $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); - - $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); - $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; - $this->assertEquals(12.7, $fixedProductTax['amount']['value']); - $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); - } - - /** - * CatalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescription settings data provider - * - * @return array - */ - public function catalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescriptionSettingsProvider() - { - return [ + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, + ], + 'displayValue' => 'EXCLUDING_FPT', + ], [ - 'weeTaxSettings' => [ - 'tax/calculation/price_includes_tax' => '1', - 'tax/display/type' => '1', - 'tax/weee/enable' => '1', - 'tax/weee/display' => '1', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '1', - ] - ] + 'weeTaxSettingsDisplayExcluded' => [ + 'tax/weee/enable' => '0', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, + ], + 'displayValue' => 'NONE', + ], ]; } /** - * Catalog Prices : Including Tax - * Catalog Display setting: Including Tax - * FPT Display setting: Including FPT Only + * FPT Display setting shuffled * * @param array $weeTaxSettings * @return void * - * @dataProvider catalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnlySettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php - */ - public function testCatalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnly(array $weeTaxSettings) - { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); - - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); - - $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - - // final price and regular price are the sum of product price and FPT - $this->assertEquals(112.7, $product['price_range']['minimum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['minimum_price']['final_price']['value']); - - $this->assertEquals(112.7, $product['price_range']['maximum_price']['regular_price']['value']); - $this->assertEquals(112.7, $product['price_range']['maximum_price']['final_price']['value']); - - $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); - $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; - $this->assertEquals(12.7, $fixedProductTax['amount']['value']); - $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); - } - - /** - * CatalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnly settings data provider - * - * @return array + * @dataProvider differentFPTDisplaySettingsProvider */ - public function catalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnlySettingsProvider() + public function testDifferentFPTDisplaySettings(array $weeTaxSettings) { - return [ - [ - 'weeTaxSettings' => [ - 'tax/calculation/price_includes_tax' => '1', - 'tax/display/type' => '2', - 'tax/weee/enable' => '1', - 'tax/weee/display' => '0', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '0', - ] - ] - ]; - } - - /** - * Catalog Prices : Including Tax - * Catalog Display setting: Including Tax - * FPT Display setting: Including FPT and FPT Description - * Apply Tax to FPT = Yes - * - * @param array $weeTaxSettings - * @return void - * - * @dataProvider catalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPTSettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php - */ - public function testCatalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPT( - array $weeTaxSettings - ) { /** @var WriterInterface $configWriter */ $configWriter = $this->objectManager->get(WriterInterface::class); @@ -479,215 +144,59 @@ public function testCatalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithT /** @var ScopeConfigInterface $scopeConfig */ $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); $scopeConfig->clean(); - /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ - $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); - $taxClassCollection = $taxClassCollectionFactory->create(); - /** @var TaxClassModel $taxClass */ - $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); - $taxClass = $taxClassCollection->getFirstItem(); - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); - /** @var Product $product1 */ - $product1 = $productRepository->get('simple-with-ftp'); - $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); - $productRepository->save($product1); - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); + $query = $this->getStoreConfigQuery(); $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - - //12.7 + 7.5% of 12.7 = 13.65 - $fptWithTax = round(13.65, 2); - // final price and regular price are the sum of product price and FPT - $this->assertEquals(113.65, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); - $this->assertEquals(113.65, round($product['price_range']['minimum_price']['final_price']['value'], 2)); - - $this->assertEquals(113.65, round($product['price_range']['maximum_price']['regular_price']['value'], 2)); - $this->assertEquals(113.65, round($product['price_range']['maximum_price']['final_price']['value'], 2)); - - $this->assertNotEmpty($product['price_range']['minimum_price']['fixed_product_taxes']); - $fixedProductTax = $product['price_range']['minimum_price']['fixed_product_taxes'][0]; - $this->assertEquals($fptWithTax, round($fixedProductTax['amount']['value'], 2)); - $this->assertEquals('fpt_for_all_front_label', $fixedProductTax['label']); - } - - /** - * CatalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPT settings data provider - * - * @return array - */ - public function catalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPTSettingsProvider() - { - return [ - [ - 'weeTaxSettings' => [ - 'tax/calculation/price_includes_tax' > '1', - 'tax/display/type' => '2', - 'tax/weee/enable' => '1', - 'tax/weee/display' => '0', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '1', - ] - ] - ]; - } - /** - * Use multiple FPTs per product with the below tax/fpt configurations - * - * Catalog Prices : Including Tax - * Catalog Display setting: Including Tax - * FPT Display setting: Including FPT and FPT description - * Apply tax on FPT : Yes - * - * @param array $weeTaxSettings - * @return void - * - * @dataProvider catalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSettingsProvider - * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php - * @magentoApiDataFixture Magento/Weee/_files/fixed_product_attribute.php - * @magentoApiDataFixture Magento/GraphQl/Tax/_files/tax_rule_for_region_1.php - */ - public function testCatalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTs(array $weeTaxSettings) - { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); + $this->assertNotEmpty($result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['category_fixed_product_tax_display_setting']); + $this->assertNotEmpty($result['storeConfig']['sales_fixed_product_tax_display_setting']); - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); - - /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ - $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); - $taxClassCollection = $taxClassCollectionFactory->create(); - /** @var TaxClassModel $taxClass */ - $taxClassCollection->addFieldToFilter('class_type', TaxClassModel::TAX_CLASS_TYPE_PRODUCT); - $taxClass = $taxClassCollection->getFirstItem(); - /** @var ProductRepositoryInterface $productRepository */ - $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); - /** @var Product $product1 */ - $product1 = $productRepository->get('simple-with-ftp'); - $product1->setCustomAttribute('tax_class_id', $taxClass->getClassId()); - $product1->setFixedProductAttribute( - [['website_id' => 0, 'country' => 'US', 'state' => 0, 'price' => 10, 'delete' => '']] - ); - $productRepository->save($product1); - - $skus = ['simple-with-ftp']; - $query = $this->getProductQuery($skus); - $result = $this->graphQlQuery($query); - $this->assertArrayNotHasKey('errors', $result); - $this->assertNotEmpty($result['products']['items']); - $product = $result['products']['items'][0]; - $this->assertEquals(124.40, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); - $this->assertCount( - 2, - $product['price_range']['minimum_price']['fixed_product_taxes'], - 'Fixed product tax count is incorrect' + $this->assertEquals('INCLUDING_FPT', $result['storeConfig']['product_fixed_product_tax_display_setting']); + $this->assertEquals( + 'INCLUDING_FPT_AND_FPT_DESCRIPTION', + $result['storeConfig']['category_fixed_product_tax_display_setting'] ); - $this->assertResponseFields( - $product['price_range']['minimum_price']['fixed_product_taxes'], - [ - [ - 'amount' => [ - 'value' => 13.6525 - ], - 'label' => 'fpt_for_all_front_label' - ], - [ - 'amount' => [ - 'value' => 10.75 - ], - 'label' => 'fixed_product_attribute_front_label' - ], - ] + $this->assertEquals( + 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', + $result['storeConfig']['sales_fixed_product_tax_display_setting'] ); } /** - * CatalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSettingsProvider settings data provider + * DifferentFPTDisplaySettings settings data provider * * @return array */ - public function catalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSettingsProvider() + public function differentFPTDisplaySettingsProvider() { return [ [ - 'weeTaxSettings' => [ - 'tax/calculation/price_includes_tax' => '1', - 'tax/display/type' => '2', + 'weeTaxSettingsDisplay' => [ 'tax/weee/enable' => '1', - 'tax/weee/display' => '1', - 'tax/defaults/region' => '1', - 'tax/weee/apply_vat' => '1', + Config::XML_PATH_FPT_DISPLAY_PRODUCT_VIEW => WeeeDisplayConfig::DISPLAY_INCL, + Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL_DESCR, + Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, ] - ] + ], ]; } /** - * Get GraphQl query to fetch products by sku + * Get GraphQl query to fetch storeConfig and FPT serttings * - * @param array $skus * @return string */ - private function getProductQuery(array $skus): string + private function getStoreConfigQuery(): string { - $stringSkus = '"' . implode('","', $skus) . '"'; return <<<QUERY { - products(filter: {sku: {in: [$stringSkus]}}, sort: {name: ASC}) { - items { - name - sku - price_range { - minimum_price { - regular_price { - value - currency - } - final_price { - value - currency - } - discount { - amount_off - percent_off - } - fixed_product_taxes{ - amount{value} - label - } - } - maximum_price { - regular_price { - value - currency - } - final_price { - value - currency - } - discount { - amount_off - percent_off - } - fixed_product_taxes - { - amount{value} - label - } - } - } + storeConfig { + product_fixed_product_tax_display_setting + category_fixed_product_tax_display_setting + sales_fixed_product_tax_display_setting } - } } QUERY; } From 0d05091e9d3d7134fdbe47e40cd4ed6a857022e5 Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Mon, 7 Oct 2019 15:50:55 -0500 Subject: [PATCH 31/61] MC-21480: Add caching for CategoryList resolver - Added CategoryList Caching resolver --- .../Category/CategoryListIdentity.php | 39 +++++++++++++++++++ .../CatalogGraphQl/etc/schema.graphqls | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php new file mode 100644 index 000000000000..3bc13803b935 --- /dev/null +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\CatalogGraphQl\Model\Resolver\Category; + +use Magento\Framework\GraphQl\Query\Resolver\IdentityInterface; + +/** + * Identity for resolved category + */ +class CategoryListIdentity implements IdentityInterface +{ + /** @var string */ + private $cacheTag = \Magento\Catalog\Model\Category::CACHE_TAG; + + /** + * Get category IDs from resolved data + * + * @param array $resolvedData + * @return string[] + */ + public function getIdentities(array $resolvedData): array + { + $ids = []; + if (!empty($resolvedData)) { + foreach ($resolvedData as $category) { + $ids[] = sprintf('%s_%s', $this->cacheTag, $category['id']); + } + if (!empty($ids)) { + array_unshift($ids, $this->cacheTag); + } + } + return $ids; + } +} diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 9c729a175ad0..170379c35d7d 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -16,7 +16,7 @@ type Query { @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") @doc(description: "The category query searches for categories that match the criteria specified in the search and filter attributes.") @deprecated(reason: "Use 'categoryList' query instead of 'category' query") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryTreeIdentity") categoryList( filters: CategoryFilterInput @doc(description: "Identifies which Category filter inputs to search for and return.") - ): [CategoryTree] @doc(description: "Returns an array of categories based on the specified filters.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") + ): [CategoryTree] @doc(description: "Returns an array of categories based on the specified filters.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryListIdentity") } type Price @doc(description: "Price is deprecated, replaced by ProductPrice. The Price object defines the price of a product as well as any tax-related adjustments.") { From b1b1af4631b64ccc5cd90b1113f675cd4fdd2ac9 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 7 Oct 2019 16:18:18 -0500 Subject: [PATCH 32/61] MC-21491: Pricing :: FPT display settings - test weee disabled --- .../GraphQl/Weee/ProductPriceWithFPTTest.php | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php index 6bf851287458..7ddf417d34db 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php @@ -632,6 +632,74 @@ public function catalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSetti ]; } + /** + * Test FPT disabled feature + * + * FPT enabled : FALSE + * + * @param array $weeTaxSettings + * @return void + * + * @dataProvider catalogPriceDisabledFPTSettingsProvider + * @magentoApiDataFixture Magento/Weee/_files/product_with_fpt.php + */ + public function testCatalogPriceDisableFPT(array $weeTaxSettings) + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); + + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + /** @var Product $product1 */ + $product1 = $productRepository->get('simple-with-ftp'); + $product1->setFixedProductAttribute( + [['website_id' => 0, 'country' => 'US', 'state' => 0, 'price' => 10, 'delete' => '']] + ); + $productRepository->save($product1); + + $skus = ['simple-with-ftp']; + $query = $this->getProductQuery($skus); + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertNotEmpty($result['products']['items']); + $product = $result['products']['items'][0]; + $this->assertEquals(100, round($product['price_range']['minimum_price']['regular_price']['value'], 2)); + $this->assertCount( + 0, + $product['price_range']['minimum_price']['fixed_product_taxes'], + 'Fixed product tax count is incorrect' + ); + $this->assertResponseFields( + $product['price_range']['minimum_price']['fixed_product_taxes'], + [] + ); + } + + /** + * CatalogPriceDisableFPT settings data provider + * + * @return array + */ + public function catalogPriceDisabledFPTSettingsProvider() + { + return [ + [ + 'weeTaxSettings' => [ + 'tax/weee/enable' => '0', + 'tax/weee/display' => '1', + ], + ], + ]; + } + /** * Get GraphQl query to fetch products by sku * From 56a068e25ad45eeda6bdc5405c38c036c922834a Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Mon, 7 Oct 2019 17:20:43 -0500 Subject: [PATCH 33/61] MC-21480: Add caching for CategoryList resolver - Made changes to caching test and resolver --- .../Category/CategoryListIdentity.php | 39 ------------ .../CatalogGraphQl/etc/schema.graphqls | 2 +- .../Catalog/CategoryListCacheTest.php | 62 +++++++++++++++++++ 3 files changed, 63 insertions(+), 40 deletions(-) delete mode 100644 app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php deleted file mode 100644 index 3bc13803b935..000000000000 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Category/CategoryListIdentity.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -declare(strict_types=1); - -namespace Magento\CatalogGraphQl\Model\Resolver\Category; - -use Magento\Framework\GraphQl\Query\Resolver\IdentityInterface; - -/** - * Identity for resolved category - */ -class CategoryListIdentity implements IdentityInterface -{ - /** @var string */ - private $cacheTag = \Magento\Catalog\Model\Category::CACHE_TAG; - - /** - * Get category IDs from resolved data - * - * @param array $resolvedData - * @return string[] - */ - public function getIdentities(array $resolvedData): array - { - $ids = []; - if (!empty($resolvedData)) { - foreach ($resolvedData as $category) { - $ids[] = sprintf('%s_%s', $this->cacheTag, $category['id']); - } - if (!empty($ids)) { - array_unshift($ids, $this->cacheTag); - } - } - return $ids; - } -} diff --git a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls index 456c61dd1a18..536992d3fca8 100644 --- a/app/code/Magento/CatalogGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CatalogGraphQl/etc/schema.graphqls @@ -16,7 +16,7 @@ type Query { @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryTree") @doc(description: "The category query searches for categories that match the criteria specified in the search and filter attributes.") @deprecated(reason: "Use 'categoryList' query instead of 'category' query") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryTreeIdentity") categoryList( filters: CategoryFilterInput @doc(description: "Identifies which Category filter inputs to search for and return.") - ): [CategoryTree] @doc(description: "Returns an array of categories based on the specified filters.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoryListIdentity") + ): [CategoryTree] @doc(description: "Returns an array of categories based on the specified filters.") @resolver(class: "Magento\\CatalogGraphQl\\Model\\Resolver\\CategoryList") @cache(cacheIdentity: "Magento\\CatalogGraphQl\\Model\\Resolver\\Category\\CategoriesIdentity") } type Price @doc(description: "Price is deprecated, replaced by ProductPrice. The Price object defines the price of a product as well as any tax-related adjustments.") { diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php index b91e55267896..3f3c3d960603 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php @@ -77,4 +77,66 @@ public function testSecondRequestIsServedFromCache() $actualCacheTags = explode(',', $cacheResponse->getHeader('X-Magento-Tags')->getFieldValue()); $this->assertEquals($expectedCacheTags, $actualCacheTags); } + + /** + * Test cache tags are generated + * + * @magentoDataFixture Magento/Catalog/_files/category_tree.php + */ + public function testRequestCacheTagsForCategoryListOnMultipleIds(): void + { + $categoryId1 ='400'; + $categoryId2 = '401'; + $query + = <<<QUERY + { + categoryList(filters: {ids: {in: ["$categoryId1", "$categoryId2"]}}) { + id + name + url_key + description + product_count + } + } +QUERY; + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); + $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); + $expectedCacheTags = ['cat_c','cat_c_' . $categoryId1, 'cat_c_' . $categoryId2, 'FPC']; + $this->assertEquals($expectedCacheTags, $actualCacheTags); + } + + /** + * Test request is served from cache + * + * @magentoDataFixture Magento/Catalog/_files/category_tree.php + */ + public function testSecondRequestIsServedFromCacheOnMultipleIds() + { + $categoryId1 ='400'; + $categoryId2 = '401'; + $query + = <<<QUERY + { + categoryList(filters: {ids: {in: ["$categoryId1", "$categoryId2"]}}) { + id + name + url_key + description + product_count + } + } +QUERY; + $expectedCacheTags = ['cat_c','cat_c_' . $categoryId1, 'cat_c_' . $categoryId2, 'FPC']; + + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); + $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); + $this->assertEquals($expectedCacheTags, $actualCacheTags); + + $cacheResponse = $this->dispatchGraphQlGETRequest(['query' => $query]); + $this->assertEquals('HIT', $cacheResponse->getHeader('X-Magento-Cache-Debug')->getFieldValue()); + $actualCacheTags = explode(',', $cacheResponse->getHeader('X-Magento-Tags')->getFieldValue()); + $this->assertEquals($expectedCacheTags, $actualCacheTags); + } } From d0a266450c44744df1f2f82eaa40b6edc58b1224 Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Tue, 8 Oct 2019 10:10:23 -0500 Subject: [PATCH 34/61] MC-15986: Category Filtering - Handle match filters --- .../Model/Category/CategoryFilter.php | 52 +++++++++++++------ .../Model/Resolver/CategoryList.php | 50 +++++++++++------- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php index 8de0d13e51e9..2c03550404ae 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php +++ b/app/code/Magento/CatalogGraphQl/Model/Category/CategoryFilter.php @@ -8,8 +8,12 @@ namespace Magento\CatalogGraphQl\Model\Category; use Magento\Catalog\Api\Data\CategoryInterface; -use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory; use Magento\Catalog\Model\ResourceModel\Category\Collection; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Exception\InputException; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Search\Model\Query; /** * Category filter allows to filter collection using 'id, url_key, name' from search criteria. @@ -17,17 +21,17 @@ class CategoryFilter { /** - * @var CollectionFactory + * @var ScopeConfigInterface */ - private $collectionFactory; + private $scopeConfig; /** - * @param CollectionFactory $collectionFactory + * @param ScopeConfigInterface $scopeConfig */ public function __construct( - CollectionFactory $collectionFactory + ScopeConfigInterface $scopeConfig ) { - $this->collectionFactory = $collectionFactory; + $this->scopeConfig = $scopeConfig; } /** @@ -35,46 +39,64 @@ public function __construct( * * @param array $args * @param Collection $categoryCollection + * @param StoreInterface $store + * @throws InputException */ - public function applyFilters( - array $args, - Collection $categoryCollection - ): void { + public function applyFilters(array $args, Collection $categoryCollection, StoreInterface $store) + { $categoryCollection->addAttributeToFilter(CategoryInterface::KEY_IS_ACTIVE, ['eq' => 1]); foreach ($args['filters'] as $field => $cond) { foreach ($cond as $condType => $value) { if ($field === 'ids') { $categoryCollection->addIdFilter($value); } else { - $this->addAttributeFilter($categoryCollection, $field, $condType, $value); + $this->addAttributeFilter($categoryCollection, $field, $condType, $value, $store); } } } } /** + * Add filter to category collection + * * @param Collection $categoryCollection * @param string $field * @param string $condType * @param string|array $value + * @param StoreInterface $store + * @throws InputException */ - private function addAttributeFilter($categoryCollection, $field, $condType, $value) + private function addAttributeFilter($categoryCollection, $field, $condType, $value, $store) { if ($condType === 'match') { - $this->addMatchFilter($categoryCollection, $field, $value); + $this->addMatchFilter($categoryCollection, $field, $value, $store); return; } $categoryCollection->addAttributeToFilter($field, [$condType => $value]); } /** + * Add match filter to collection * * @param Collection $categoryCollection * @param string $field * @param string $value + * @param StoreInterface $store + * @throws InputException */ - private function addMatchFilter($categoryCollection, $field, $value) + private function addMatchFilter($categoryCollection, $field, $value, $store) { - $categoryCollection->addAttributeToFilter($field, ['like' => "%{$value}%"]); + $minQueryLength = $this->scopeConfig->getValue( + Query::XML_PATH_MIN_QUERY_LENGTH, + ScopeInterface::SCOPE_STORE, + $store + ); + $searchValue = str_replace('%', '', $value); + $matchLength = strlen($searchValue); + if ($matchLength < $minQueryLength) { + throw new InputException(__('Invalid match filter')); + } + + $categoryCollection->addAttributeToFilter($field, ['like' => "%{$searchValue}%"]); } } diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php index 5e51791593cb..b0132c0e9bf4 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php @@ -7,8 +7,8 @@ namespace Magento\CatalogGraphQl\Model\Resolver; -use Magento\CatalogGraphQl\Model\Resolver\Category\CheckCategoryIsActive; use Magento\CatalogGraphQl\Model\Resolver\Products\DataProvider\ExtractDataFromCategoryTree; +use Magento\Framework\Exception\InputException; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; @@ -42,28 +42,20 @@ class CategoryList implements ResolverInterface */ private $extractDataFromCategoryTree; - /** - * @var CheckCategoryIsActive - */ - private $checkCategoryIsActive; - /** * @param CategoryTree $categoryTree * @param ExtractDataFromCategoryTree $extractDataFromCategoryTree - * @param CheckCategoryIsActive $checkCategoryIsActive * @param CategoryFilter $categoryFilter * @param CollectionFactory $collectionFactory */ public function __construct( CategoryTree $categoryTree, ExtractDataFromCategoryTree $extractDataFromCategoryTree, - CheckCategoryIsActive $checkCategoryIsActive, CategoryFilter $categoryFilter, CollectionFactory $collectionFactory ) { $this->categoryTree = $categoryTree; $this->extractDataFromCategoryTree = $extractDataFromCategoryTree; - $this->checkCategoryIsActive = $checkCategoryIsActive; $this->categoryFilter = $categoryFilter; $this->collectionFactory = $collectionFactory; } @@ -76,25 +68,47 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value if (isset($value[$field->getName()])) { return $value[$field->getName()]; } - $categoryCollection = $this->collectionFactory->create(); + $store = $context->getExtensionAttributes()->getStore(); + $rootCategoryIds = []; if (!isset($args['filters'])) { - $rootCategoryIds = [(int)$context->getExtensionAttributes()->getStore()->getRootCategoryId()]; + $rootCategoryIds[] = (int)$store->getRootCategoryId(); } else { - $this->categoryFilter->applyFilters($args, $categoryCollection); - $rootCategoryIds = []; + $categoryCollection = $this->collectionFactory->create(); + try { + $this->categoryFilter->applyFilters($args, $categoryCollection, $store); + } catch (InputException $e) { + return []; + } + foreach ($categoryCollection as $category) { $rootCategoryIds[] = (int)$category->getId(); } } - $result = []; - foreach ($rootCategoryIds as $rootCategoryId) { - $categoryTree = $this->categoryTree->getTree($info, $rootCategoryId); + + $result = $this->fetchCategories($rootCategoryIds, $info); + return $result; + } + + /** + * Fetch category tree data + * + * @param array $categoryIds + * @param ResolveInfo $info + * @return array + * @throws GraphQlNoSuchEntityException + */ + private function fetchCategories(array $categoryIds, ResolveInfo $info) + { + $fetchedCategories = []; + foreach ($categoryIds as $categoryId) { + $categoryTree = $this->categoryTree->getTree($info, $categoryId); if (empty($categoryTree)) { throw new GraphQlNoSuchEntityException(__('Category doesn\'t exist')); } - $result[] = current($this->extractDataFromCategoryTree->execute($categoryTree)); + $fetchedCategories[] = current($this->extractDataFromCategoryTree->execute($categoryTree)); } - return $result; + + return $fetchedCategories; } } From 99832232e567a87106e316a68bcec3360100ac5d Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Tue, 8 Oct 2019 11:05:16 -0500 Subject: [PATCH 35/61] MC-15986: Category Filtering - additional test cases --- .../Model/Resolver/CategoryList.php | 2 +- .../GraphQl/Catalog/CategoryListTest.php | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php index b0132c0e9bf4..6b8949d61282 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/CategoryList.php @@ -104,7 +104,7 @@ private function fetchCategories(array $categoryIds, ResolveInfo $info) foreach ($categoryIds as $categoryId) { $categoryTree = $this->categoryTree->getTree($info, $categoryId); if (empty($categoryTree)) { - throw new GraphQlNoSuchEntityException(__('Category doesn\'t exist')); + continue; } $fetchedCategories[] = current($this->extractDataFromCategoryTree->execute($categoryTree)); } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php index cbf09ca5d2e6..9a1d891fc41e 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php @@ -7,6 +7,8 @@ namespace Magento\GraphQl\Catalog; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\GraphQlAbstract; /** @@ -239,6 +241,64 @@ public function testNoResultsFound() $this->assertEquals([], $result['categoryList']); } + /** + * When no filters are supplied, the root category is returned + * + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + */ + public function testEmptyFiltersReturnRootCategory() + { + $query = <<<QUERY +{ + categoryList{ + id + name + url_key + url_path + children_count + path + position + } +} +QUERY; + + $storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); + $storeRootCategoryId = $storeManager->getStore()->getRootCategoryId(); + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertArrayHasKey('categoryList', $result); + $this->assertEquals('Default Category', $result['categoryList'][0]['name']); + $this->assertEquals($storeRootCategoryId, $result['categoryList'][0]['id']); + } + + /** + * Filtering with match value less than minimum query should return empty result + * + * @magentoApiDataFixture Magento/Catalog/_files/categories.php + */ + public function testMinimumMatchQueryLength() + { + $query = <<<QUERY +{ + categoryList(filters: {name: {match: "mo"}}){ + id + name + url_key + url_path + children_count + path + position + } +} +QUERY; + + $result = $this->graphQlQuery($query); + $this->assertArrayNotHasKey('errors', $result); + $this->assertArrayHasKey('categoryList', $result); + $this->assertEquals([], $result['categoryList']); + } + /** * @return array */ From 823599d8efda05d8ffebfa3267a951a94a1a5ebe Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Tue, 8 Oct 2019 12:54:18 -0500 Subject: [PATCH 36/61] MC-21491: Pricing :: FPT display settings - fix static --- app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php index 49c034185d80..58d2f54a670e 100644 --- a/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php +++ b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php @@ -16,6 +16,9 @@ use Magento\Weee\Model\Tax as WeeeDisplayConfig; use Magento\Framework\Pricing\Render; +/** + * Resolver for the FPT store config settings + */ class StoreConfig implements ResolverInterface { /** From 2a0536c58dbcad905c91aa49407459677d7e0934 Mon Sep 17 00:00:00 2001 From: Anusha Vattam <avattam@adobe.com> Date: Tue, 8 Oct 2019 14:16:17 -0500 Subject: [PATCH 37/61] MC-15986: Category Filtering - Fixed static and integartion build failures --- .../Magento/GraphQl/Catalog/CategoryListTest.php | 11 +---------- .../Controller/Catalog/CategoryListCacheTest.php | 7 +++++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php index 9a1d891fc41e..0e88af2fcb22 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Catalog/CategoryListTest.php @@ -16,7 +16,6 @@ */ class CategoryListTest extends GraphQlAbstract { - /** * @magentoApiDataFixture Magento/Catalog/_files/categories.php * @dataProvider filterSingleCategoryDataProvider @@ -39,7 +38,6 @@ public function testFilterSingleCategoryByField($field, $condition, $value, $exp } } QUERY; - $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); $this->assertCount(1, $result['categoryList']); @@ -69,7 +67,6 @@ public function testFilterMultipleCategoriesByField($field, $condition, $value, } } QUERY; - $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); $this->assertCount(count($expectedResult), $result['categoryList']); @@ -96,7 +93,6 @@ public function testFilterCategoryByMultipleFields() } } QUERY; - $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); $this->assertCount(3, $result['categoryList']); @@ -121,7 +117,6 @@ public function testFilterWithInactiveCategory() } } QUERY; - $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); $this->assertCount(1, $result['categoryList']); @@ -168,9 +163,7 @@ public function testQueryChildCategoriesWithProducts() } } QUERY; - $result = $this->graphQlQuery($query); - $a = 3; $this->assertArrayNotHasKey('errors', $result); $this->assertCount(1, $result['categoryList']); @@ -234,7 +227,6 @@ public function testNoResultsFound() } } QUERY; - $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); $this->assertArrayHasKey('categoryList', $result); @@ -261,7 +253,6 @@ public function testEmptyFiltersReturnRootCategory() } } QUERY; - $storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); $storeRootCategoryId = $storeManager->getStore()->getRootCategoryId(); @@ -292,7 +283,6 @@ public function testMinimumMatchQueryLength() } } QUERY; - $result = $this->graphQlQuery($query); $this->assertArrayNotHasKey('errors', $result); $this->assertArrayHasKey('categoryList', $result); @@ -351,6 +341,7 @@ public function filterSingleCategoryDataProvider(): array } /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) * @return array */ public function filterMultipleCategoriesDataProvider(): array diff --git a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php index 3f3c3d960603..a8e9059a84eb 100644 --- a/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php +++ b/dev/tests/integration/testsuite/Magento/GraphQlCache/Controller/Catalog/CategoryListCacheTest.php @@ -99,10 +99,12 @@ public function testRequestCacheTagsForCategoryListOnMultipleIds(): void } } QUERY; + //added the previous category in expected tags as it is cached + $expectedCacheTags = ['cat_c','cat_c_' .'333', 'cat_c_' . $categoryId1, 'cat_c_' . $categoryId2, 'FPC']; + $response = $this->dispatchGraphQlGETRequest(['query' => $query]); $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); $actualCacheTags = explode(',', $response->getHeader('X-Magento-Tags')->getFieldValue()); - $expectedCacheTags = ['cat_c','cat_c_' . $categoryId1, 'cat_c_' . $categoryId2, 'FPC']; $this->assertEquals($expectedCacheTags, $actualCacheTags); } @@ -127,7 +129,8 @@ public function testSecondRequestIsServedFromCacheOnMultipleIds() } } QUERY; - $expectedCacheTags = ['cat_c','cat_c_' . $categoryId1, 'cat_c_' . $categoryId2, 'FPC']; + //added the previous category in expected tags as it is cached + $expectedCacheTags = ['cat_c','cat_c_' .'333', 'cat_c_' . $categoryId1, 'cat_c_' . $categoryId2, 'FPC']; $response = $this->dispatchGraphQlGETRequest(['query' => $query]); $this->assertEquals('MISS', $response->getHeader('X-Magento-Cache-Debug')->getFieldValue()); From 325ea6e845864497aa3c416cfd39611a09b0afb4 Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Tue, 8 Oct 2019 15:16:46 -0500 Subject: [PATCH 38/61] MC-19013: Scheduled update is not created by the admin from not default site - fixed - added integration test --- .../Catalog/Model/Product/Hydrator.php | 37 +++++++++ app/code/Magento/Catalog/etc/di.xml | 2 +- .../Catalog/Model/ProductHydratorTest.php | 75 +++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Catalog/Model/Product/Hydrator.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/ProductHydratorTest.php diff --git a/app/code/Magento/Catalog/Model/Product/Hydrator.php b/app/code/Magento/Catalog/Model/Product/Hydrator.php new file mode 100644 index 000000000000..9cae124c1abf --- /dev/null +++ b/app/code/Magento/Catalog/Model/Product/Hydrator.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Model\Product; + +use Magento\Framework\EntityManager\HydratorInterface; + +/** + * Class is used to extract data and populate entity with data + */ +class Hydrator implements HydratorInterface +{ + /** + * @inheritdoc + */ + public function extract($entity) + { + return $entity->getData(); + } + + /** + * @inheritdoc + */ + public function hydrate($entity, array $data) + { + $lockedAttributes = $entity->getLockedAttributes(); + $entity->unlockAttributes(); + $entity->setData(array_merge($entity->getData(), $data)); + foreach ($lockedAttributes as $attribute) { + $entity->lockAttribute($attribute); + } + + return $entity; + } +} diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 570fa6e7f9ef..a6753176d8e1 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -867,7 +867,7 @@ <argument name="hydrators" xsi:type="array"> <item name="Magento\Catalog\Api\Data\CategoryInterface" xsi:type="string">Magento\Framework\EntityManager\AbstractModelHydrator</item> <item name="Magento\Catalog\Api\Data\CategoryTreeInterface" xsi:type="string">Magento\Framework\EntityManager\AbstractModelHydrator</item> - <item name="Magento\Catalog\Api\Data\ProductInterface" xsi:type="string">Magento\Framework\EntityManager\AbstractModelHydrator</item> + <item name="Magento\Catalog\Api\Data\ProductInterface" xsi:type="string">\Magento\Catalog\Model\Product\Hydrator</item> </argument> </arguments> </type> diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductHydratorTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductHydratorTest.php new file mode 100644 index 000000000000..948170218332 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ProductHydratorTest.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Catalog\Model; + +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Framework\EntityManager\HydratorInterface; +use Magento\Framework\EntityManager\HydratorPool; +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Test Product Hydrator + */ +class ProductHydratorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Bootstrap + */ + private $objectManager; + + /** + * @var HydratorPool + */ + private $hydratorPool; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->hydratorPool = $this->objectManager->create(HydratorPool::class); + } + + /** + * Test that Hydrator correctly populates entity with data + */ + public function testProductHydrator() + { + $addAttributes = [ + 'sku' => 'product_updated', + 'name' => 'Product (Updated)', + 'type_id' => 'simple', + 'status' => 1, + ]; + + /** @var Product $product */ + $product = $this->objectManager->create(Product::class); + $product->setId(42) + ->setSku('product') + ->setName('Product') + ->setPrice(10) + ->setQty(123); + $product->lockAttribute('sku'); + $product->lockAttribute('type_id'); + $product->lockAttribute('price'); + + /** @var HydratorInterface $hydrator */ + $hydrator = $this->hydratorPool->getHydrator(ProductInterface::class); + $hydrator->hydrate($product, $addAttributes); + + $expected = [ + 'entity_id' => 42, + 'sku' => 'product_updated', + 'name' => 'Product (Updated)', + 'type_id' => 'simple', + 'status' => 1, + 'price' => 10, + 'qty' => 123, + ]; + $this->assertEquals($expected, $product->getData()); + } +} From 21889b9e3408449fde5aef1e0463e6d6a0b606bf Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Wed, 9 Oct 2019 01:14:25 -0500 Subject: [PATCH 39/61] MC-19013: Scheduled update is not created by the admin from not default site - static tests --- 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 a6753176d8e1..ff2fab73e037 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -867,7 +867,7 @@ <argument name="hydrators" xsi:type="array"> <item name="Magento\Catalog\Api\Data\CategoryInterface" xsi:type="string">Magento\Framework\EntityManager\AbstractModelHydrator</item> <item name="Magento\Catalog\Api\Data\CategoryTreeInterface" xsi:type="string">Magento\Framework\EntityManager\AbstractModelHydrator</item> - <item name="Magento\Catalog\Api\Data\ProductInterface" xsi:type="string">\Magento\Catalog\Model\Product\Hydrator</item> + <item name="Magento\Catalog\Api\Data\ProductInterface" xsi:type="string">Magento\Catalog\Model\Product\Hydrator</item> </argument> </arguments> </type> From 07c8f546d45a3066e6e6e237bed33bad555745be Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Wed, 9 Oct 2019 14:50:17 -0500 Subject: [PATCH 40/61] MC-20158: Redirects are not supported in urlResolver - support for custom urls - return the proper canonical url --- .../Model/Resolver/Product/CanonicalUrl.php | 4 +- .../Model/Resolver/EntityUrl.php | 66 ++++++++++++++----- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php index 9047eaee4b56..9616c54676bb 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php @@ -34,8 +34,8 @@ public function resolve( /* @var $product Product */ $product = $value['model']; - $url = $product->getUrlModel()->getUrl($product, ['_ignore_category' => true]); + $product->getUrlModel()->getUrl($product, ['_ignore_category' => true]); - return $url; + return $product->getRequestPath(); } } diff --git a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php index 0acece9271f7..bd728863b51e 100644 --- a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php +++ b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php @@ -57,6 +57,7 @@ public function resolve( throw new GraphQlInputException(__('"url" argument should be specified and not empty')); } + $storeId = (int)$context->getExtensionAttributes()->getStore()->getId(); $result = null; $url = $args['url']; if (substr($url, 0, 1) === '/' && $url !== '/') { @@ -64,42 +65,71 @@ public function resolve( } $customUrl = $this->customUrlLocator->locateUrl($url); $url = $customUrl ?: $url; - $urlRewrite = $this->findCanonicalUrl($url, (int)$context->getExtensionAttributes()->getStore()->getId()); - if ($urlRewrite) { - if (!$urlRewrite->getEntityId()) { + $finalUrlRewrite = $this->findFinalUrl($url, $storeId); + if ($finalUrlRewrite) { + $relativeUrl = $finalUrlRewrite->getRequestPath(); + $resultArray = $this->rewriteCustomUrls($finalUrlRewrite, $storeId) ?? [ + 'id' => $finalUrlRewrite->getEntityId(), + 'canonical_url' => $relativeUrl, + 'relative_url' => $relativeUrl, + 'type' => $this->sanitizeType($finalUrlRewrite->getEntityType()) + ]; + + + if (empty($resultArray['id'])) { throw new GraphQlNoSuchEntityException( __('No such entity found with matching URL key: %url', ['url' => $url]) ); } - $result = [ - 'id' => $urlRewrite->getEntityId(), - 'canonical_url' => $urlRewrite->getTargetPath(), - 'relative_url' => $urlRewrite->getTargetPath(), - 'type' => $this->sanitizeType($urlRewrite->getEntityType()) - ]; + + $result = $resultArray; } return $result; } /** - * Find the canonical url passing through all redirects if any + * Handle custom urls with and without redirects + * + * @param UrlRewrite $finalUrlRewrite + * @param int $storeId + * @return array|null + */ + private function rewriteCustomUrls(UrlRewrite $finalUrlRewrite, int $storeId): ?array + { + if ($finalUrlRewrite->getEntityType() === 'custom' || !($finalUrlRewrite->getEntityId() > 0)) { + $finalCustomUrlRewrite = clone $finalUrlRewrite; + $finalUrlRewrite = $this->findFinalUrl($finalCustomUrlRewrite->getTargetPath(), $storeId, true); + $relativeUrl = + $finalCustomUrlRewrite->getRedirectType() == 0 + ? $finalCustomUrlRewrite->getRequestPath() : $finalUrlRewrite->getRequestPath(); + return [ + 'id' => $finalUrlRewrite->getEntityId(), + 'canonical_url' => $relativeUrl, + 'relative_url' => $relativeUrl, + 'type' => $this->sanitizeType($finalUrlRewrite->getEntityType()) + ]; + } + return null; + } + + /** + * Find the final url passing through all redirects if any * * @param string $requestPath * @param int $storeId + * @param bool $findCustom * @return UrlRewrite|null */ - private function findCanonicalUrl(string $requestPath, int $storeId) : ?UrlRewrite + private function findFinalUrl(string $requestPath, int $storeId, bool $findCustom = false): ?UrlRewrite { $urlRewrite = $this->findUrlFromRequestPath($requestPath, $storeId); - if ($urlRewrite && $urlRewrite->getRedirectType() > 0) { - while ($urlRewrite && $urlRewrite->getRedirectType() > 0) { - $urlRewrite = $this->findUrlFromRequestPath($urlRewrite->getTargetPath(), $storeId); - } + while ($urlRewrite && $urlRewrite->getRedirectType() > 0) { + $urlRewrite = $this->findUrlFromRequestPath($urlRewrite->getTargetPath(), $storeId); } if (!$urlRewrite) { $urlRewrite = $this->findUrlFromTargetPath($requestPath, $storeId); } - if ($urlRewrite && !$urlRewrite->getEntityId() && !$urlRewrite->getIsAutogenerated()) { + if ($urlRewrite && ($findCustom && !$urlRewrite->getEntityId() && !$urlRewrite->getIsAutogenerated())) { $urlRewrite = $this->findUrlFromTargetPath($urlRewrite->getTargetPath(), $storeId); } @@ -113,7 +143,7 @@ private function findCanonicalUrl(string $requestPath, int $storeId) : ?UrlRewri * @param int $storeId * @return UrlRewrite|null */ - private function findUrlFromRequestPath(string $requestPath, int $storeId) : ?UrlRewrite + private function findUrlFromRequestPath(string $requestPath, int $storeId): ?UrlRewrite { return $this->urlFinder->findOneByData( [ @@ -130,7 +160,7 @@ private function findUrlFromRequestPath(string $requestPath, int $storeId) : ?Ur * @param int $storeId * @return UrlRewrite|null */ - private function findUrlFromTargetPath(string $targetPath, int $storeId) : ?UrlRewrite + private function findUrlFromTargetPath(string $targetPath, int $storeId): ?UrlRewrite { return $this->urlFinder->findOneByData( [ From 3c40e617c63037008216ad5ddc7e1634c14eb8dd Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Wed, 9 Oct 2019 16:02:30 -0500 Subject: [PATCH 41/61] MC-19013: Scheduled update is not created by the admin from not default site - fixed not related issue integration test that failed due to lack of isolation --- .../testsuite/Magento/Sales/_files/quotes.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quotes.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quotes.php index b916fc024041..98acdda2b43f 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/quotes.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quotes.php @@ -7,6 +7,8 @@ use Magento\Quote\Model\QuoteFactory; use Magento\Quote\Model\QuoteRepository; +use Magento\Store\Api\Data\StoreInterface; +use Magento\Store\Model\StoreManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\ObjectManager; @@ -18,18 +20,22 @@ $quoteFactory = $objectManager->get(QuoteFactory::class); /** @var QuoteRepository $quoteRepository */ $quoteRepository = $objectManager->get(QuoteRepository::class); +/** @var StoreManager $storeManager */ +$storeManager = $objectManager->get(StoreManager::class); $quotes = [ 'quote for first store' => [ - 'store' => 1, + 'store' => 'default', ], 'quote for second store' => [ - 'store' => 2, + 'store' => 'fixture_second_store', ], ]; foreach ($quotes as $quoteData) { $quote = $quoteFactory->create(); - $quote->setStoreId($quoteData['store']); + /** @var StoreInterface $store */ + $store = $storeManager->getStore($quoteData['store']); + $quote->setStoreId($store->getId()); $quoteRepository->save($quote); } From e5a83c04bc474fa2c95706d62e61a319480ea4be Mon Sep 17 00:00:00 2001 From: Daniel Renaud <drenaud@magento.com> Date: Wed, 9 Oct 2019 16:10:56 -0500 Subject: [PATCH 42/61] MC-15986: Category Filtering - Add performance test for multiple categories --- setup/performance-toolkit/benchmark.jmx | 148 ++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index ddc52133d75d..b6154e136131 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -40573,6 +40573,154 @@ function assertCategoryChildren(category, response) { </hashTree> + <ThroughputController guiclass="ThroughputControllerGui" testclass="ThroughputController" testname="GraphQL Get Multiple Categories" enabled="true"> + <intProp name="ThroughputController.style">1</intProp> + <boolProp name="ThroughputController.perThread">false</boolProp> + <intProp name="ThroughputController.maxThroughput">1</intProp> + <stringProp name="ThroughputController.percentThroughput">${graphqlGetCategoryListByCategoryIdPercentage}</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/_system/scenario_controller_tmpl.jmx</stringProp></ThroughputController> + <hashTree> + <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="Set Test Label" enabled="true"> + <stringProp name="script"> +var testLabel = "${testLabel}" ? " (${testLabel})" : ""; +if (testLabel + && sampler.getClass().getName() == 'org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy' +) { + if (sampler.getName().indexOf(testLabel) == -1) { + sampler.setName(sampler.getName() + testLabel); + } +} else if (sampler.getName().indexOf("SetUp - ") == -1) { + sampler.setName("SetUp - " + sampler.getName()); +} + </stringProp> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/_system/setup_label.jmx</stringProp></JSR223PreProcessor> + <hashTree/> + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - Set Label" enabled="true"> + <stringProp name="BeanShellSampler.query"> + vars.put("testLabel", "GraphQL Get Multiple Categories"); + </stringProp> + <boolProp name="BeanShellSampler.resetInterpreter">true</boolProp> + </BeanShellSampler> + <hashTree/> + + <HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="HTTP Header Manager" enabled="true"> + <collectionProp name="HeaderManager.headers"> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Content-Type</stringProp> + <stringProp name="Header.value">application/json</stringProp> + </elementProp> + <elementProp name="" elementType="Header"> + <stringProp name="Header.name">Accept</stringProp> + <stringProp name="Header.value">*/*</stringProp> + </elementProp> + </collectionProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/api/header_manager_before_token.jmx</stringProp></HeaderManager> + <hashTree/> + + <BeanShellSampler guiclass="BeanShellSamplerGui" testclass="BeanShellSampler" testname="SetUp - Init Random Generator" enabled="true"> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/init_random_generator_setup.jmx</stringProp> + <stringProp name="BeanShellSampler.query"> +import java.util.Random; + +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom} + ${__threadNum}); +} + +vars.putObject("randomIntGenerator", random); + </stringProp> + <stringProp name="BeanShellSampler.filename"/> + <stringProp name="BeanShellSampler.parameters"/> + <boolProp name="BeanShellSampler.resetInterpreter">true</boolProp> + </BeanShellSampler> + <hashTree/> + + <JSR223Sampler guiclass="TestBeanGUI" testclass="JSR223Sampler" testname="SetUp - Prepare Category Data" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script">random = vars.getObject("randomIntGenerator"); + +var categories = props.get("categories"); + +var numbers = []; + +var sanity = 0; +for(var i = 0; i < 4; i++){ + sanity++; + if(sanity > 100){ + break; + } + var number = random.nextInt(categories.length) + if(numbers.indexOf(number) >= 0){ + i--; + continue; + } + numbers.push(number); +} + +vars.put("category_id_1", categories[numbers[0]].id); +vars.put("category_id_2", categories[numbers[1]].id); +vars.put("category_id_3", categories[numbers[2]].id); +vars.put("category_id_4", categories[numbers[3]].id); +</stringProp> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/common/extract_multiple_categories_setup.jmx</stringProp> + </JSR223Sampler> + <hashTree/> + + <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Get multiple categories by ID" enabled="true"> + <boolProp name="HTTPSampler.postBodyRaw">true</boolProp> + <elementProp name="HTTPsampler.Arguments" elementType="Arguments"> + <collectionProp name="Arguments.arguments"> + <elementProp name="" elementType="HTTPArgument"> + <boolProp name="HTTPArgument.always_encode">false</boolProp> + <stringProp name="Argument.value">{"query" : "{\n categoryList(filters:{ids: {in: [\"${category_id_1}\", \"${category_id_2}\", \"${category_id_3}\", \"${category_id_4}\"]}}) {\n id\n children {\n id\n name\n url_key\n url_path\n children_count\n path\n image\n productImagePreview: products(pageSize: 1, sort: {name: ASC}) {\n items {\n small_image {\n label\n url\n }\n }\n }\n }\n }\n}"}</stringProp> + <stringProp name="Argument.metadata">=</stringProp> + </elementProp> + </collectionProp> + </elementProp> + <stringProp name="HTTPSampler.domain"/> + <stringProp name="HTTPSampler.port">${graphql_port_number}</stringProp> + <stringProp name="HTTPSampler.connect_timeout">60000</stringProp> + <stringProp name="HTTPSampler.response_timeout">200000</stringProp> + <stringProp name="HTTPSampler.protocol">${request_protocol}</stringProp> + <stringProp name="HTTPSampler.contentEncoding"/> + <stringProp name="HTTPSampler.path">${base_path}graphql</stringProp> + <stringProp name="HTTPSampler.method">POST</stringProp> + <boolProp name="HTTPSampler.follow_redirects">true</boolProp> + <boolProp name="HTTPSampler.auto_redirects">false</boolProp> + <boolProp name="HTTPSampler.use_keepalive">true</boolProp> + <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp> + <boolProp name="HTTPSampler.monitor">false</boolProp> + <stringProp name="HTTPSampler.embedded_url_re"/> + <stringProp name="TestPlan.comments">mpaf/tool/fragments/ce/graphql/get_multiple_categories_by_id.jmx</stringProp> + </HTTPSamplerProxy> + <hashTree> + <JSR223Assertion guiclass="TestBeanGUI" testclass="JSR223Assertion" testname="Assert category count" enabled="true"> + <stringProp name="scriptLanguage">javascript</stringProp> + <stringProp name="parameters"/> + <stringProp name="filename"/> + <stringProp name="cacheKey"/> + <stringProp name="script">var response = JSON.parse(prev.getResponseDataAsString()); + +if(response.data == undefined || response.data.categoryList == undefined){ + AssertionResult.setFailureMessage("CategoryList results are empty."); + AssertionResult.setFailure(true); +} + +if(response.data.categoryList.length !== 4){ + AssertionResult.setFailureMessage("CategoryList query expected to find 4 categories. " + response.data.categoryList.length + " returned."); + AssertionResult.setFailure(true); +} +</stringProp> + </JSR223Assertion> + <hashTree/> + </hashTree> + </hashTree> + + <ThroughputController guiclass="ThroughputControllerGui" testclass="ThroughputController" testname="GraphQL Get Url Info by url_key" enabled="true"> <intProp name="ThroughputController.style">1</intProp> <boolProp name="ThroughputController.perThread">false</boolProp> From 2665d816fb85b68985b4fe1e4d663bb6481d01bb Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Wed, 9 Oct 2019 17:03:49 -0500 Subject: [PATCH 43/61] MC-20158: Redirects are not supported in urlResolver - fix test --- .../CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php index 9616c54676bb..9047eaee4b56 100644 --- a/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php +++ b/app/code/Magento/CatalogGraphQl/Model/Resolver/Product/CanonicalUrl.php @@ -34,8 +34,8 @@ public function resolve( /* @var $product Product */ $product = $value['model']; - $product->getUrlModel()->getUrl($product, ['_ignore_category' => true]); + $url = $product->getUrlModel()->getUrl($product, ['_ignore_category' => true]); - return $product->getRequestPath(); + return $url; } } From 2f0a792cc473740490cf657c60fc6c3d0cca2728 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Thu, 10 Oct 2019 15:31:40 -0500 Subject: [PATCH 44/61] MC-20158: Redirects are not supported in urlResolver - add tests - fix test --- .../CatalogUrlRewrite/UrlResolverTest.php | 182 ++++++++++++++++-- .../GraphQl/CmsUrlRewrite/UrlResolverTest.php | 25 ++- 2 files changed, 185 insertions(+), 22 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index b15cfe3a5b91..05a6b04b3630 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -12,6 +12,7 @@ use Magento\TestFramework\TestCase\GraphQlAbstract; use Magento\UrlRewrite\Model\UrlFinderInterface; use Magento\UrlRewrite\Model\UrlRewrite; +use Magento\UrlRewrite\Model\UrlPersistInterface; /** * Test the GraphQL endpoint's URLResolver query to verify canonical URL's are correctly returned. @@ -65,7 +66,7 @@ public function testProductUrlResolver() 'store_id' => $storeId ] ); - $targetPath = $actualUrls->getTargetPath(); + $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); $query @@ -82,16 +83,16 @@ public function testProductUrlResolver() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } /** - * Tests the use case where relative_url is provided as resolver input in the Query + * Tests the use case where non seo friendly is provided as resolver input in the Query * * @magentoApiDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php */ - public function testProductUrlWithCanonicalUrlInput() + public function testProductUrlWithNonSeoFriendlyUrlInput() { $productSku = 'p002'; /** @var ProductRepositoryInterface $productRepository */ @@ -122,13 +123,14 @@ public function testProductUrlWithCanonicalUrlInput() 'store_id' => $storeId ] ); - $targetPath = $actualUrls->getTargetPath(); + // even of non seo friendly path requested, the seo friendly path should be prefered + $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); - $canonicalPath = $actualUrls->getTargetPath(); + $nonSeoFriendlyPath = $actualUrls->getTargetPath(); $query = <<<QUERY { - urlResolver(url:"{$canonicalPath}") + urlResolver(url:"{$nonSeoFriendlyPath}") { id relative_url @@ -139,10 +141,158 @@ public function testProductUrlWithCanonicalUrlInput() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } + + /** + * Tests the use case where non seo friendly is provided as resolver input in the Query + * + * @magentoApiDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php + */ + public function testRedirectsAndCustomInput() + { + $productSku = 'p002'; + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $product = $productRepository->get($productSku, false, null, true); + + // generate permanent redirects + $renamedKey = 'p002-ren'; + $product->setUrlKey($renamedKey); + $product->setData('save_rewrites_history', true); + $product->save(); + + $storeId = $product->getStoreId(); + + $query + = <<<QUERY +{ + products(filter: {sku: {eq: "{$productSku}"}}) + { + items { + url_key + url_suffix + } + } +} +QUERY; + $response = $this->graphQlQuery($query); + $urlPath = $response['products']['items'][0]['url_key'] . $response['products']['items'][0]['url_suffix']; + + /** @var UrlFinderInterface $urlFinder */ + $urlFinder = $this->objectManager->get(UrlFinderInterface::class); + $actualUrls = $urlFinder->findOneByData( + [ + 'request_path' => $urlPath, + 'store_id' => $storeId + ] + ); + // querying the end redirect gives the same record + $relativePath = $actualUrls->getRequestPath(); + $expectedType = $actualUrls->getEntityType(); + $query + = <<<QUERY +{ + urlResolver(url:"{$renamedKey}.html") + { + id + relative_url + type + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayHasKey('urlResolver', $response); + $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); + $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + + + // querying a url that's a redirect the active redirected final url + $query + = <<<QUERY +{ + urlResolver(url:"{$productSku}.html") + { + id + relative_url + type + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayHasKey('urlResolver', $response); + $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); + $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + + + // create custom url that doesn't redirect + /** @var UrlRewrite $urlRewriteModel */ + $urlRewriteModel = $this->objectManager->create(UrlRewrite::class); + + $customUrl = 'custom-path'; + $urlRewriteArray = [ + 'entity_type' => 'custom', + 'entity_id' => '0', + 'request_path' => $customUrl, + 'target_path' => 'p002.html', + 'redirect_type' => '0', + 'store_id' => '1', + 'description' => '', + 'is_autogenerated' => '0', + 'metadata' => null, + ]; + foreach ($urlRewriteArray as $key => $value) { + $urlRewriteModel->setData($key, $value); + } + $urlRewriteModel->save(); + + // querying a custom url that should return the target entity but relative should be the custom url + $query + = <<<QUERY +{ + urlResolver(url:"{$customUrl}") + { + id + relative_url + type + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayHasKey('urlResolver', $response); + $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); + $this->assertEquals($customUrl, $response['urlResolver']['relative_url']); + $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + + + // change custom url that does redirect + $urlRewriteModel->setRedirectType('301'); + $urlRewriteModel->setId($urlRewriteModel->getId()); + $urlRewriteModel->save(); + + //modifying query to avoid getting cached values. + $query + = <<<QUERY +{ + urlResolver(url:"{$customUrl}") + { + id relative_url type + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayHasKey('urlResolver', $response); + $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); + $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + + $urlRewriteModel->delete(); + } + /** * Test for category entity * @@ -166,7 +316,7 @@ public function testCategoryUrlResolver() ] ); $categoryId = $actualUrls->getEntityId(); - $targetPath = $actualUrls->getTargetPath(); + $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); $query @@ -195,7 +345,7 @@ public function testCategoryUrlResolver() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($categoryId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } @@ -238,7 +388,7 @@ public function testProductUrlRewriteResolver() 'store_id' => $storeId ] ); - $targetPath = $actualUrls->getTargetPath(); + $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); $query = <<<QUERY @@ -254,7 +404,7 @@ public function testProductUrlRewriteResolver() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } @@ -319,7 +469,7 @@ public function testCategoryUrlWithLeadingSlash() ] ); $categoryId = $actualUrls->getEntityId(); - $targetPath = $actualUrls->getTargetPath(); + $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); $query @@ -347,7 +497,7 @@ public function testCategoryUrlWithLeadingSlash() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($categoryId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); } @@ -371,7 +521,7 @@ public function testGetNonExistentUrlRewrite() 'store_id' => 1 ] ); - $targetPath = $actualUrls->getTargetPath(); + $relativePath = $actualUrls->getRequestPath(); $query = <<<QUERY { @@ -386,6 +536,6 @@ public function testGetNonExistentUrlRewrite() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals('PRODUCT', $response['urlResolver']['type']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php index ece421925a31..de165ca39159 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php @@ -58,7 +58,24 @@ public function testCMSPageUrlResolver() QUERY; $response = $this->graphQlQuery($query); $this->assertEquals($cmsPageId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($requestPath, $response['urlResolver']['relative_url']); + $this->assertEquals(strtoupper(str_replace('-', '_', $expectedEntityType)), $response['urlResolver']['type']); + + // querying by non seo friendly url path should return seo friendly relative url + $query + = <<<QUERY +{ + urlResolver(url:"{$targetPath}") + { + id + relative_url + type + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertEquals($cmsPageId, $response['urlResolver']['id']); + $this->assertEquals($requestPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper(str_replace('-', '_', $expectedEntityType)), $response['urlResolver']['type']); } @@ -77,10 +94,6 @@ public function testResolveSlash() $page = $this->objectManager->get(\Magento\Cms\Model\Page::class); $page->load($homePageIdentifier); $homePageId = $page->getId(); - /** @var \Magento\CmsUrlRewrite\Model\CmsPageUrlPathGenerator $urlPathGenerator */ - $urlPathGenerator = $this->objectManager->get(\Magento\CmsUrlRewrite\Model\CmsPageUrlPathGenerator::class); - /** @param \Magento\Cms\Api\Data\PageInterface $page */ - $targetPath = $urlPathGenerator->getCanonicalUrlPath($page); $query = <<<QUERY { @@ -95,7 +108,7 @@ public function testResolveSlash() $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($homePageId, $response['urlResolver']['id']); - $this->assertEquals($targetPath, $response['urlResolver']['relative_url']); + $this->assertEquals($homePageIdentifier, $response['urlResolver']['relative_url']); $this->assertEquals('CMS_PAGE', $response['urlResolver']['type']); } } From 05dacc606460314f7bdbd46645eb842ab661e022 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Wed, 9 Oct 2019 16:53:42 -0500 Subject: [PATCH 45/61] MC-21491: Pricing :: FPT display settings - fix test --- .../GraphQl/Weee/ProductPriceWithFPTTest.php | 149 +++++++----------- 1 file changed, 59 insertions(+), 90 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php index 40f83e747505..9f3cad6bcb6c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php @@ -27,12 +27,61 @@ class ProductPriceWithFPTTest extends GraphQlAbstract /** @var ObjectManager $objectManager */ private $objectManager; + /** @var string[] $objectManager */ + private $initialConfig; + + /** @var ScopeConfigInterface */ + private $scopeConfig; + /** * @inheritdoc */ - protected function setUp() :void + protected function setUp(): void { $this->objectManager = Bootstrap::getObjectManager(); + + /** @var ScopeConfigInterface $scopeConfig */ + $this->scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + + $currentSettingsArray = [ + 'tax/display/type', + 'tax/weee/enable', + 'tax/weee/display', + 'tax/defaults/region', + 'tax/weee/apply_vat', + 'tax/calculation/price_includes_tax' + ]; + + foreach ($currentSettingsArray as $configPath) { + $this->initialConfig[$configPath] = $this->scopeConfig->getValue( + $configPath + ); + } + } + + /** + * @inheritdoc + */ + protected function tearDown(): void + { + $this->writeConfig($this->initialConfig); + } + + /** + * Write configuration for weee + * + * @param array $weeTaxSettings + * @return void + */ + private function writeConfig(array $weeTaxSettings): void + { + /** @var WriterInterface $configWriter */ + $configWriter = $this->objectManager->get(WriterInterface::class); + + foreach ($weeTaxSettings as $path => $value) { + $configWriter->save($path, $value); + } + $this->scopeConfig->clean(); } /** @@ -49,16 +98,7 @@ protected function setUp() :void */ public function testCatalogPriceExcludeTaxAndIncludeFPTOnly(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); $skus = ['simple-with-ftp']; $query = $this->getProductQuery($skus); @@ -115,16 +155,7 @@ public function catalogPriceExcludeTaxAndIncludeFPTOnlySettingsProvider() */ public function testCatalogPriceExcludeTaxAndIncludeFPTWithDescription(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); $skus = ['simple-with-ftp']; $query = $this->getProductQuery($skus); @@ -181,16 +212,7 @@ public function catalogPriceExcludeTaxAndIncludeFPTWithDescriptionSettingsProvid */ public function testCatalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnly(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); @@ -257,16 +279,7 @@ public function catalogPriceExcludeTaxCatalogDisplayIncludeTaxAndIncludeFPTOnlyS */ public function testCatalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescription(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); @@ -333,16 +346,7 @@ public function catalogPriceExclTaxCatalogDisplayInclTaxAndInclFPTWithDescriptio */ public function testCatalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescription(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); $skus = ['simple-with-ftp']; $query = $this->getProductQuery($skus); @@ -400,16 +404,7 @@ public function catalogPriceInclTaxCatalogDisplayExclTaxAndInclFPTWithDescriptio */ public function testCatalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnly(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); $skus = ['simple-with-ftp']; $query = $this->getProductQuery($skus); @@ -469,16 +464,8 @@ public function catalogPriceInclTaxCatalogDisplayInclTaxAndInclFPTOnlySettingsPr public function testCatalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAppliedOnFPT( array $weeTaxSettings ) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } + $this->writeConfig($weeTaxSettings); - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); $taxClassCollection = $taxClassCollectionFactory->create(); @@ -552,16 +539,7 @@ public function catalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAp */ public function testCatalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTs(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); /** @var TaxClassCollectionFactory $taxClassCollectionFactory */ $taxClassCollectionFactory = $this->objectManager->get(TaxClassCollectionFactory::class); @@ -644,16 +622,7 @@ public function catalogPriceInclTaxCatalogDisplayIncludeTaxAndMuyltipleFPTsSetti */ public function testCatalogPriceDisableFPT(array $weeTaxSettings) { - /** @var WriterInterface $configWriter */ - $configWriter = $this->objectManager->get(WriterInterface::class); - - foreach ($weeTaxSettings as $path => $value) { - $configWriter->save($path, $value); - } - - /** @var ScopeConfigInterface $scopeConfig */ - $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); - $scopeConfig->clean(); + $this->writeConfig($weeTaxSettings); /** @var ProductRepositoryInterface $productRepository */ $productRepository = $this->objectManager->get(ProductRepositoryInterface::class); From bf40eca40440b8efbdfa0bc5c0466e850decd11e Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Thu, 10 Oct 2019 16:50:33 -0500 Subject: [PATCH 46/61] MC-21491: Pricing :: FPT display settings - fix test --- .../Magento/GraphQl/Tax/ProductViewTest.php | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php index 048ccb70af0d..f3179fedfeb2 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php @@ -38,6 +38,13 @@ class ProductViewTest extends GraphQlAbstract /** @var \Magento\Tax\Model\Calculation\Rule[] */ private $fixtureTaxRules; + /** @var string */ + private $defaultRegionSystemSetting; + + + /** @var string */ + private $defaultPriceDisplayType; + /** * @var StoreManagerInterface */ @@ -52,19 +59,26 @@ protected function setUp() /** @var \Magento\Config\Model\ResourceModel\Config $config */ $config = $this->objectManager->get(\Magento\Config\Model\ResourceModel\Config::class); + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + + $this->defaultRegionSystemSetting = $scopeConfig->getValue( + Config::CONFIG_XML_PATH_DEFAULT_REGION + ); + + $this->defaultPriceDisplayType = $scopeConfig->getValue( + Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE + ); + //default state tax calculation AL $config->saveConfig( Config::CONFIG_XML_PATH_DEFAULT_REGION, - 1, - ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 1 ); $config->saveConfig( Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE, - 3, - ScopeConfigInterface::SCOPE_TYPE_DEFAULT, - 1 + 3 ); $this->getFixtureTaxRates(); $this->getFixtureTaxRules(); @@ -72,6 +86,9 @@ protected function setUp() /** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */ $config = $this->objectManager->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class); $config->reinit(); + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); } public function tearDown() @@ -82,16 +99,12 @@ public function tearDown() //default state tax calculation AL $config->saveConfig( Config::CONFIG_XML_PATH_DEFAULT_REGION, - null, - ScopeConfigInterface::SCOPE_TYPE_DEFAULT, - 1 + $this->defaultRegionSystemSetting ); $config->saveConfig( Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE, - 1, - ScopeConfigInterface::SCOPE_TYPE_DEFAULT, - 1 + $this->defaultPriceDisplayType ); $taxRules = $this->getFixtureTaxRules(); if (count($taxRules)) { @@ -107,6 +120,10 @@ public function tearDown() /** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */ $config = $this->objectManager->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class); $config->reinit(); + + /** @var ScopeConfigInterface $scopeConfig */ + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $scopeConfig->clean(); } /** From b42dfb005635e78403963b49ac04adb1dd7ced52 Mon Sep 17 00:00:00 2001 From: Oleksandr Dubovyk <odubovyk@magento.com> Date: Thu, 10 Oct 2019 17:13:56 -0500 Subject: [PATCH 47/61] MC-19013: Scheduled update is not created by the admin from not default site - added strict type --- app/code/Magento/Catalog/Model/Product/Hydrator.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Catalog/Model/Product/Hydrator.php b/app/code/Magento/Catalog/Model/Product/Hydrator.php index 9cae124c1abf..dcdce7202b21 100644 --- a/app/code/Magento/Catalog/Model/Product/Hydrator.php +++ b/app/code/Magento/Catalog/Model/Product/Hydrator.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Product; use Magento\Framework\EntityManager\HydratorInterface; From 9f64ae60296325b324b90ceeabf8b997d8079bfc Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Fri, 11 Oct 2019 09:19:31 -0500 Subject: [PATCH 48/61] MC-21491: Pricing :: FPT display settings - fix test --- .../Magento/GraphQl/Tax/ProductViewTest.php | 22 +++++- .../GraphQl/Weee/ProductPriceWithFPTTest.php | 78 +++++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php index f3179fedfeb2..2f33d3f46a10 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php @@ -270,6 +270,22 @@ private function getFixtureTaxRules() */ private function assertBaseFields($product, $actualResponse) { + $pricesTypes = [ + 'minimalPrice', + 'regularPrice', + 'maximalPrice', + ]; + foreach ($pricesTypes as $priceType) { + if (isset($actualResponse['price'][$priceType]['amount']['value'])) { + $actualResponse['price'][$priceType]['amount']['value'] = + round($actualResponse['price'][$priceType]['amount']['value'], 4); + } + + if (isset($actualResponse['price'][$priceType]['adjustments'][0]['amount']['value'])) { + $actualResponse['price'][$priceType]['adjustments'][0]['amount']['value'] = + round($actualResponse['price'][$priceType]['adjustments'][0]['amount']['value'], 4); + } + } // product_object_field_name, expected_value $assertionMap = [ ['response_field' => 'attribute_set_id', 'expected_value' => $product->getAttributeSetId()], @@ -288,7 +304,7 @@ private function assertBaseFields($product, $actualResponse) [ 'amount' => [ - 'value' => 0.286501, + 'value' => 0.2865, 'currency' => 'USD', ], 'code' => 'TAX', @@ -306,7 +322,7 @@ private function assertBaseFields($product, $actualResponse) [ 'amount' => [ - 'value' => 0.750001, + 'value' => 0.7500, 'currency' => 'USD', ], 'code' => 'TAX', @@ -324,7 +340,7 @@ private function assertBaseFields($product, $actualResponse) [ 'amount' => [ - 'value' => 0.286501, + 'value' => 0.2865, 'currency' => 'USD', ], 'code' => 'TAX', diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php index 9f3cad6bcb6c..979fc2a2217f 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php @@ -33,6 +33,13 @@ class ProductPriceWithFPTTest extends GraphQlAbstract /** @var ScopeConfigInterface */ private $scopeConfig; + + /** @var \Magento\Tax\Model\Calculation\Rate[] */ + private $fixtureTaxRates; + + /** @var \Magento\Tax\Model\Calculation\Rule[] */ + private $fixtureTaxRules; + /** * @inheritdoc */ @@ -52,11 +59,28 @@ protected function setUp(): void 'tax/calculation/price_includes_tax' ]; + + $this->getFixtureTaxRates(); + $this->getFixtureTaxRules(); + $taxRules = $this->getFixtureTaxRules(); + if (count($taxRules)) { + $taxRates = $this->getFixtureTaxRates(); + foreach ($taxRules as $taxRule) { + $taxRule->delete(); + } + foreach ($taxRates as $taxRate) { + $taxRate->delete(); + } + } + foreach ($currentSettingsArray as $configPath) { $this->initialConfig[$configPath] = $this->scopeConfig->getValue( $configPath ); } + /** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */ + $config = $this->objectManager->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class); + $config->reinit(); } /** @@ -64,6 +88,17 @@ protected function setUp(): void */ protected function tearDown(): void { + $taxRules = $this->getFixtureTaxRules(); + if (count($taxRules)) { + $taxRates = $this->getFixtureTaxRates(); + foreach ($taxRules as $taxRule) { + $taxRule->delete(); + } + foreach ($taxRates as $taxRate) { + $taxRate->delete(); + } + } + $this->writeConfig($this->initialConfig); } @@ -727,4 +762,47 @@ private function getProductQuery(array $skus): string } QUERY; } + + /** + * Get tax rates created in Magento\Tax\_files\tax_rule_region_1_al.php + * + * @return \Magento\Tax\Model\Calculation\Rate[] + */ + private function getFixtureTaxRates() + { + if ($this->fixtureTaxRates === null) { + $this->fixtureTaxRates = []; + if ($this->getFixtureTaxRules()) { + $taxRateIds = (array)$this->getFixtureTaxRules()[0]->getRates(); + foreach ($taxRateIds as $taxRateId) { + /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ + $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class); + $this->fixtureTaxRates[] = $taxRate->load($taxRateId); + } + } + } + return $this->fixtureTaxRates; + } + + /** + * Get tax rule created in Magento\Tax\_files\tax_rule_region_1_al.php + * + * @return \Magento\Tax\Model\Calculation\Rule[] + */ + private function getFixtureTaxRules() + { + if ($this->fixtureTaxRules === null) { + $this->fixtureTaxRules = []; + $taxRuleCodes = ['AL Test Rule']; + foreach ($taxRuleCodes as $taxRuleCode) { + /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ + $taxRule = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rule::class); + $taxRule->load($taxRuleCode, 'code'); + if ($taxRule->getId()) { + $this->fixtureTaxRules[] = $taxRule; + } + } + } + return $this->fixtureTaxRules; + } } From d30965b3f4167da6f9de6ba60f9e0f4f72b6375e Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Fri, 11 Oct 2019 13:55:32 -0500 Subject: [PATCH 49/61] MC-21491: Pricing :: FPT display settings - fix test --- .../GraphQl/Weee/ProductPriceWithFPTTest.php | 66 +------------------ 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php index 979fc2a2217f..4e88ee50f4bf 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php @@ -33,13 +33,6 @@ class ProductPriceWithFPTTest extends GraphQlAbstract /** @var ScopeConfigInterface */ private $scopeConfig; - - /** @var \Magento\Tax\Model\Calculation\Rate[] */ - private $fixtureTaxRates; - - /** @var \Magento\Tax\Model\Calculation\Rule[] */ - private $fixtureTaxRules; - /** * @inheritdoc */ @@ -59,20 +52,6 @@ protected function setUp(): void 'tax/calculation/price_includes_tax' ]; - - $this->getFixtureTaxRates(); - $this->getFixtureTaxRules(); - $taxRules = $this->getFixtureTaxRules(); - if (count($taxRules)) { - $taxRates = $this->getFixtureTaxRates(); - foreach ($taxRules as $taxRule) { - $taxRule->delete(); - } - foreach ($taxRates as $taxRate) { - $taxRate->delete(); - } - } - foreach ($currentSettingsArray as $configPath) { $this->initialConfig[$configPath] = $this->scopeConfig->getValue( $configPath @@ -546,7 +525,7 @@ public function catalogPriceIncTaxCatalogDisplayInclTaxInclFPTWithDescrWithTaxAp return [ [ 'weeTaxSettings' => [ - 'tax/calculation/price_includes_tax' > '1', + 'tax/calculation/price_includes_tax' => '1', 'tax/display/type' => '2', 'tax/weee/enable' => '1', 'tax/weee/display' => '0', @@ -762,47 +741,4 @@ private function getProductQuery(array $skus): string } QUERY; } - - /** - * Get tax rates created in Magento\Tax\_files\tax_rule_region_1_al.php - * - * @return \Magento\Tax\Model\Calculation\Rate[] - */ - private function getFixtureTaxRates() - { - if ($this->fixtureTaxRates === null) { - $this->fixtureTaxRates = []; - if ($this->getFixtureTaxRules()) { - $taxRateIds = (array)$this->getFixtureTaxRules()[0]->getRates(); - foreach ($taxRateIds as $taxRateId) { - /** @var \Magento\Tax\Model\Calculation\Rate $taxRate */ - $taxRate = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rate::class); - $this->fixtureTaxRates[] = $taxRate->load($taxRateId); - } - } - } - return $this->fixtureTaxRates; - } - - /** - * Get tax rule created in Magento\Tax\_files\tax_rule_region_1_al.php - * - * @return \Magento\Tax\Model\Calculation\Rule[] - */ - private function getFixtureTaxRules() - { - if ($this->fixtureTaxRules === null) { - $this->fixtureTaxRules = []; - $taxRuleCodes = ['AL Test Rule']; - foreach ($taxRuleCodes as $taxRuleCode) { - /** @var \Magento\Tax\Model\Calculation\Rule $taxRule */ - $taxRule = Bootstrap::getObjectManager()->create(\Magento\Tax\Model\Calculation\Rule::class); - $taxRule->load($taxRuleCode, 'code'); - if ($taxRule->getId()) { - $this->fixtureTaxRules[] = $taxRule; - } - } - } - return $this->fixtureTaxRules; - } } From 431224c9f77b79ba3eb44003a0ab65d605296da1 Mon Sep 17 00:00:00 2001 From: Buba Suma <soumah@adobe.com> Date: Thu, 10 Oct 2019 17:09:38 -0500 Subject: [PATCH 50/61] MC-21699: Tax does not change when changing the billing address from Admin Panel - Fix shipping_as_billing is set to 0 when shipping_method is changed --- .../Controller/Adminhtml/Order/Create.php | 2 +- .../ActionGroup/AdminOrderActionGroup.xml | 28 +++++-- .../AdminOrderFormBillingAddressSection.xml | 3 +- .../Section/AdminOrderFormPaymentSection.xml | 1 + ...thTwoAddressesTaxableAndNonTaxableTest.xml | 75 +++++++++++++++++++ 5 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderForCustomerWithTwoAddressesTaxableAndNonTaxableTest.xml diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php index 341ee16ae910..45cd504be201 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php @@ -188,7 +188,7 @@ protected function _processActionData($action = null) && $this->_getOrderCreateModel()->getShippingAddress()->getSameAsBilling() && empty($shippingMethod) ) { $this->_getOrderCreateModel()->setShippingAsBilling(1); - } else { + } elseif ($syncFlag !== null) { $this->_getOrderCreateModel()->setShippingAsBilling((int)$syncFlag); } } diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index 3f178ae02102..90e2aa8e1252 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -92,7 +92,7 @@ <annotations> <description>Clears the Email, First Name, Last Name, Street Line 1, City, Postal Code and Phone fields when adding an Order and then verifies that they are required after attempting to Save.</description> </annotations> - + <seeElement selector="{{AdminOrderFormAccountSection.requiredGroup}}" stepKey="seeCustomerGroupRequired"/> <seeElement selector="{{AdminOrderFormAccountSection.requiredEmail}}" stepKey="seeEmailRequired"/> <clearField selector="{{AdminOrderFormAccountSection.email}}" stepKey="clearEmailField"/> @@ -181,7 +181,7 @@ <annotations> <description>EXTENDS: addConfigurableProductToOrder. Selects the provided Option to the Configurable Product.</description> </annotations> - + <waitForElementVisible selector="{{AdminOrderFormConfigureProductSection.optionSelect(attribute.default_frontend_label)}}" stepKey="waitForConfigurablePopover"/> <selectOption selector="{{AdminOrderFormConfigureProductSection.optionSelect(attribute.default_frontend_label)}}" userInput="{{option.label}}" stepKey="selectionConfigurableOption"/> </actionGroup> @@ -195,7 +195,7 @@ <argument name="option"/> <argument name="quantity" type="string"/> </arguments> - + <click selector="{{AdminOrderFormItemsSection.configure}}" stepKey="clickConfigure"/> <waitForElementVisible selector="{{AdminOrderFormConfigureProductSection.optionSelect(attribute.default_frontend_label)}}" stepKey="waitForConfigurablePopover"/> <wait time="2" stepKey="waitForOptionsToLoad"/> @@ -213,7 +213,7 @@ <argument name="product"/> <argument name="quantity" type="string" defaultValue="1"/> </arguments> - + <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillSkuFilterBundle"/> <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearchBundle"/> @@ -235,7 +235,7 @@ <arguments> <argument name="price" type="string"/> </arguments> - + <grabTextFrom selector="{{AdminOrderFormItemsSection.rowPrice('1')}}" stepKey="grabProductPriceFromGrid" after="clickOk"/> <assertEquals stepKey="assertProductPriceInGrid" message="Bundle product price in grid should be equal {{price}}" after="grabProductPriceFromGrid"> <expectedResult type="string">{{price}}</expectedResult> @@ -320,6 +320,22 @@ <selectOption selector="{{AdminOrderFormPaymentSection.flatRateOption}}" userInput="flatrate_flatrate" stepKey="checkFlatRate"/> </actionGroup> + <actionGroup name="changeShippingMethod"> + <annotations> + <description>Change Shipping Method on the Admin 'Create New Order for' page.</description> + </annotations> + <arguments> + <argument name="shippingMethod" defaultValue="flatrate_flatrate" type="string"/> + </arguments> + <click selector="{{AdminOrderFormPaymentSection.header}}" stepKey="unfocus"/> + <waitForPageLoad stepKey="waitForJavascriptToFinish"/> + <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="clickShippingMethods1"/> + <waitForElementVisible selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="waitForChangeShippingMethod"/> + <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="clickShippingMethods2"/> + <waitForElementVisible selector="{{AdminOrderFormPaymentSection.shippingMethod}}" stepKey="waitForShippingOptions2"/> + <selectOption selector="{{AdminOrderFormPaymentSection.shippingMethod}}" userInput="{{shippingMethod}}" stepKey="checkFlatRate"/> + </actionGroup> + <!--Select free shipping method--> <actionGroup name="orderSelectFreeShipping"> <annotations> @@ -516,7 +532,7 @@ <argument name="product"/> <argument name="customer"/> </arguments> - + <amOnPage stepKey="navigateToNewOrderPage" url="{{AdminOrderCreatePage.url}}"/> <waitForPageLoad stepKey="waitForNewOrderPageOpened"/> <click stepKey="chooseCustomer" selector="{{AdminOrdersGridSection.customerInOrdersSection(customer.firstname)}}"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBillingAddressSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBillingAddressSection.xml index 2d1a4d5a4cba..4fde9db1d21d 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBillingAddressSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBillingAddressSection.xml @@ -9,6 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminOrderFormBillingAddressSection"> + <element name="selectAddress" type="select" selector="//select[@id='order-billing_address_customer_address_id']"/> <element name="NamePrefix" type="input" selector="#order-billing_address_prefix" timeout="30"/> <element name="FirstName" type="input" selector="#order-billing_address_firstname" timeout="30"/> <element name="MiddleName" type="input" selector="#order-billing_address_middlename" timeout="30"/> @@ -38,4 +39,4 @@ <element name="postalCodeError" type="text" selector="#order-billing_address_postcode-error"/> <element name="phoneError" type="text" selector="#order-billing_address_telephone-error"/> </section> -</sections> \ No newline at end of file +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml index b31582552ccc..a478d79d8553 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormPaymentSection.xml @@ -9,6 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminOrderFormPaymentSection"> + <element name="shippingMethod" type="radio" selector="//input[@name='order[shipping_method]']"/> <element name="header" type="text" selector="#order-methods span.title"/> <element name="getShippingMethods" type="text" selector="#order-shipping_method a.action-default" timeout="30"/> <element name="flatRateOption" type="radio" selector="#s_method_flatrate_flatrate" timeout="30"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderForCustomerWithTwoAddressesTaxableAndNonTaxableTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderForCustomerWithTwoAddressesTaxableAndNonTaxableTest.xml new file mode 100644 index 000000000000..d6bf0eec301d --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderForCustomerWithTwoAddressesTaxableAndNonTaxableTest.xml @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="AdminCreateOrderForCustomerWithTwoAddressesTaxableAndNonTaxableTest"> + <annotations> + <title value="Tax should not be displayed for non taxable address"/> + <stories value="MC-21699: Tax does not change when changing the billing address from Admin Panel"/> + <description value="Tax should not be displayed for non taxable address when switching from taxable address"/> + <testCaseId value="MC-21721"/> + <features value="Sales"/> + <severity value="MAJOR"/> + <group value="Sales"/> + </annotations> + <before> + <!--Enable flat rate shipping--> + <magentoCLI command="config:set {{EnableFlatRateConfigData.path}} {{EnableFlatRateConfigData.value}}" stepKey="enableFlatRate"/> + <!--Enable free shipping method --> + <magentoCLI command="config:set {{EnableFreeShippingConfigData.path}} {{EnableFreeShippingConfigData.value}}" stepKey="enableFreeShipping"/> + <!--Create customer--> + <createData entity="Customer_With_Different_Default_Billing_Shipping_Addresses" stepKey="simpleCustomer"/> + <!--Create category--> + <createData entity="_defaultCategory" stepKey="category1"/> + <!--Create product1--> + <createData entity="_defaultProduct" stepKey="product1"> + <requiredEntity createDataKey="category1"/> + </createData> + <!--Create tax rule for US-CA--> + <createData entity="defaultTaxRule" stepKey="createTaxRule"/> + <!--Login as admin--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <!--Step 1: Create new order for customer--> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrderWithExistingCustomer"> + <argument name="customer" value="$$simpleCustomer$$"/> + </actionGroup> + <!--Step 2: Add product1 to the order--> + <actionGroup ref="addSimpleProductToOrder" stepKey="addSimpleProductToOrder"> + <argument name="product" value="$$product1$$"/> + </actionGroup> + <!--Step 2: Select taxable address as billing address--> + <selectOption selector="{{AdminOrderFormBillingAddressSection.selectAddress}}" userInput="{{US_Address_CA.state}}" stepKey="selectTaxableAddress" /> + <!--Step 3: Select FlatRate shipping method--> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShippingMethod"/> + <!--Step 4: Verify that tax is applied to the order--> + <seeElement selector="{{AdminOrderFormTotalSection.total('Tax')}}" stepKey="seeTax" /> + <!--Step 5: Select non taxable address as billing address--> + <selectOption selector="{{AdminOrderFormBillingAddressSection.selectAddress}}" userInput="{{US_Address_TX.state}}" stepKey="selectNonTaxableAddress" /> + <!--Step 6: Change shipping method to Free--> + <actionGroup ref="changeShippingMethod" stepKey="changeShippingMethod"> + <argument name="shippingMethod" value="freeshipping_freeshipping"/> + </actionGroup> + <!--Step 7: Verify that tax is not applied to the order--> + <dontSeeElement selector="{{AdminOrderFormTotalSection.total('Tax')}}" stepKey="dontSeeTax" /> + <after> + <!--Delete product1--> + <deleteData createDataKey="product1" stepKey="deleteProduct1"/> + <!--Delete category--> + <deleteData createDataKey="category1" stepKey="deleteCategory1"/> + <!--Delete customer--> + <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> + <!--Delete tax rule--> + <deleteData createDataKey="createTaxRule" stepKey="deleteTaxRule"/> + <!--Logout--> + <actionGroup ref="logout" stepKey="logout"/> + <!--Disable free shipping method --> + <magentoCLI command="config:set {{DisableFreeShippingConfigData.path}} {{DisableFreeShippingConfigData.value}}" stepKey="disableFreeShipping"/> + </after> + </test> +</tests> From b6f41a2425ffef47cb110a093bc93adb74e971e1 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Fri, 11 Oct 2019 14:51:17 -0500 Subject: [PATCH 51/61] MC-21491: Pricing :: FPT display settings - fix test --- .../Magento/GraphQl/Weee/ProductPriceWithFPTTest.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php index 4e88ee50f4bf..385e3419bbf6 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/ProductPriceWithFPTTest.php @@ -67,17 +67,6 @@ protected function setUp(): void */ protected function tearDown(): void { - $taxRules = $this->getFixtureTaxRules(); - if (count($taxRules)) { - $taxRates = $this->getFixtureTaxRates(); - foreach ($taxRules as $taxRule) { - $taxRule->delete(); - } - foreach ($taxRates as $taxRate) { - $taxRate->delete(); - } - } - $this->writeConfig($this->initialConfig); } From 709c94cf9fc3e7b04cddd46b849c3c471399a5fe Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Fri, 11 Oct 2019 16:19:55 -0500 Subject: [PATCH 52/61] MC-21491: Pricing :: FPT display settings - fix test --- .../testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php index b4427f2e3247..f7a332c22d3c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php @@ -17,8 +17,6 @@ /** * Test for storeConfig FPT config values - * - * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ class StoreConfigFPTTest extends GraphQlAbstract { From 8baea724939ba038685a8222b7e09ecc6cd84249 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 14 Oct 2019 10:07:40 -0500 Subject: [PATCH 53/61] MC-21491: Pricing :: FPT display settings - fix test --- .../CatalogUrlRewrite/UrlResolverTest.php | 235 +++++++----------- 1 file changed, 93 insertions(+), 142 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index 05a6b04b3630..deb5bb0e256c 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -12,7 +12,6 @@ use Magento\TestFramework\TestCase\GraphQlAbstract; use Magento\UrlRewrite\Model\UrlFinderInterface; use Magento\UrlRewrite\Model\UrlRewrite; -use Magento\UrlRewrite\Model\UrlPersistInterface; /** * Test the GraphQL endpoint's URLResolver query to verify canonical URL's are correctly returned. @@ -69,26 +68,16 @@ public function testProductUrlResolver() $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); - $query - = <<<QUERY -{ - urlResolver(url:"{$urlPath}") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + $this->assertResponseFromGraphQl( + (int) $product->getEntityId(), + $urlPath, + $relativePath, + $expectedType + ); } /** - * Tests the use case where non seo friendly is provided as resolver input in the Query + * Test the use case where non seo friendly is provided as resolver input in the Query * * @magentoApiDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php */ @@ -127,27 +116,17 @@ public function testProductUrlWithNonSeoFriendlyUrlInput() $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); $nonSeoFriendlyPath = $actualUrls->getTargetPath(); - $query - = <<<QUERY -{ - urlResolver(url:"{$nonSeoFriendlyPath}") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); - } + $this->assertResponseFromGraphQl( + (int) $product->getEntityId(), + $nonSeoFriendlyPath, + $relativePath, + $expectedType + ); + } /** - * Tests the use case where non seo friendly is provided as resolver input in the Query + * Test the use case where non seo friendly is provided as resolver input in the Query * * @magentoApiDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php */ @@ -180,6 +159,7 @@ public function testRedirectsAndCustomInput() QUERY; $response = $this->graphQlQuery($query); $urlPath = $response['products']['items'][0]['url_key'] . $response['products']['items'][0]['url_suffix']; + $suffix = $response['products']['items'][0]['url_suffix']; /** @var UrlFinderInterface $urlFinder */ $urlFinder = $this->objectManager->get(UrlFinderInterface::class); @@ -190,44 +170,20 @@ public function testRedirectsAndCustomInput() ] ); // querying the end redirect gives the same record - $relativePath = $actualUrls->getRequestPath(); - $expectedType = $actualUrls->getEntityType(); - $query - = <<<QUERY -{ - urlResolver(url:"{$renamedKey}.html") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); - + $this->assertResponseFromGraphQl( + (int) $product->getEntityId(), + $renamedKey . $suffix, + $actualUrls->getRequestPath(), + $actualUrls->getEntityType() + ); // querying a url that's a redirect the active redirected final url - $query - = <<<QUERY -{ - urlResolver(url:"{$productSku}.html") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); - + $this->assertResponseFromGraphQl( + (int) $product->getEntityId(), + $productSku . $suffix, + $actualUrls->getRequestPath(), + $actualUrls->getEntityType() + ); // create custom url that doesn't redirect /** @var UrlRewrite $urlRewriteModel */ @@ -251,44 +207,35 @@ public function testRedirectsAndCustomInput() $urlRewriteModel->save(); // querying a custom url that should return the target entity but relative should be the custom url - $query - = <<<QUERY -{ - urlResolver(url:"{$customUrl}") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($customUrl, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); - + $this->assertResponseFromGraphQl( + (int) $product->getEntityId(), + $customUrl, + $customUrl, + $actualUrls->getEntityType() + ); // change custom url that does redirect $urlRewriteModel->setRedirectType('301'); $urlRewriteModel->setId($urlRewriteModel->getId()); $urlRewriteModel->save(); - //modifying query to avoid getting cached values. + //modifying query by adding spaces to avoid getting cached values. $query = <<<QUERY -{ +{ urlResolver(url:"{$customUrl}") { - id relative_url type + id + relative_url + type } } QUERY; $response = $this->graphQlQuery($query); $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + $this->assertEquals($actualUrls->getRequestPath(), $response['urlResolver']['relative_url']); + $this->assertEquals(strtoupper($actualUrls->getEntityType()), $response['urlResolver']['type']); $urlRewriteModel->delete(); } @@ -331,26 +278,16 @@ public function testCategoryUrlResolver() $response = $this->graphQlQuery($query); $urlPath = $response['category']['url_key'] . $response['category']['url_suffix']; - $query - = <<<QUERY -{ - urlResolver(url:"{$urlPath}") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($categoryId, $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + $this->assertResponseFromGraphQl( + (int) $categoryId, + $urlPath, + $relativePath, + $expectedType + ); } /** - * Tests the use case where the url_key of the existing product is changed + * Test the use case where the url_key of the existing product is changed * * @magentoApiDataFixture Magento/CatalogUrlRewrite/_files/product_with_category.php */ @@ -390,22 +327,13 @@ public function testProductUrlRewriteResolver() ); $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); - $query - = <<<QUERY -{ - urlResolver(url:"{$urlPath}") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + + $this->assertResponseFromGraphQl( + (int) $product->getEntityId(), + $urlPath, + $relativePath, + $expectedType + ); } /** @@ -484,21 +412,12 @@ public function testCategoryUrlWithLeadingSlash() $response = $this->graphQlQuery($query); $urlPath = $response['category']['url_key'] . $response['category']['url_suffix']; - $query = <<<QUERY -{ - urlResolver(url:"/{$urlPath}") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($categoryId, $response['urlResolver']['id']); - $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + $this->assertResponseFromGraphQl( + (int) $categoryId, + $urlPath, + $relativePath, + $expectedType + ); } /** @@ -538,4 +457,36 @@ public function testGetNonExistentUrlRewrite() $this->assertEquals('PRODUCT', $response['urlResolver']['type']); $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); } + + /** + * Assert response from GraphQl + * + * @param string $productId + * @param string $urlKey + * @param string $relativePath + * @param string $expectedType + */ + private function assertResponseFromGraphQl( + int $productId, + string $urlKey, + string $relativePath, + string $expectedType + ): void { + $query + = <<<QUERY +{ + urlResolver(url:"{$urlKey}") + { + id + relative_url + type + } +} +QUERY; + $response = $this->graphQlQuery($query); + $this->assertArrayHasKey('urlResolver', $response); + $this->assertEquals($productId, $response['urlResolver']['id']); + $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); + $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + } } From ae419ab2eefab44ea5d7836f164b259cce04c603 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 14 Oct 2019 10:44:17 -0500 Subject: [PATCH 54/61] MC-21491: Pricing :: FPT display settings - fix test --- .../CatalogUrlRewrite/UrlResolverTest.php | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index deb5bb0e256c..8ee0c7c584c6 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -139,9 +139,7 @@ public function testRedirectsAndCustomInput() // generate permanent redirects $renamedKey = 'p002-ren'; - $product->setUrlKey($renamedKey); - $product->setData('save_rewrites_history', true); - $product->save(); + $product->setUrlKey($renamedKey)->setData('save_rewrites_history', true)->save(); $storeId = $product->getStoreId(); @@ -219,24 +217,15 @@ public function testRedirectsAndCustomInput() $urlRewriteModel->setId($urlRewriteModel->getId()); $urlRewriteModel->save(); - //modifying query by adding spaces to avoid getting cached values. - $query - = <<<QUERY -{ - urlResolver(url:"{$customUrl}") - { - id - relative_url - type - } -} -QUERY; - $response = $this->graphQlQuery($query); - $this->assertArrayHasKey('urlResolver', $response); - $this->assertEquals($product->getEntityId(), $response['urlResolver']['id']); - $this->assertEquals($actualUrls->getRequestPath(), $response['urlResolver']['relative_url']); - $this->assertEquals(strtoupper($actualUrls->getEntityType()), $response['urlResolver']['type']); + ObjectManager::getInstance()->get(\Magento\TestFramework\Helper\CacheCleaner::class)->cleanAll(); + //modifying query by adding spaces to avoid getting cached values. + $this->assertResponseFromGraphQl( + (int) $product->getEntityId(), + $customUrl, + $actualUrls->getRequestPath(), + strtoupper($actualUrls->getEntityType()) + ); $urlRewriteModel->delete(); } From c257dd46963dc9d8ec0d6254b0c407825897e171 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 14 Oct 2019 11:06:10 -0500 Subject: [PATCH 55/61] MC-21494: Graphql Weee storeCofnig Document schema changes --- .../WeeeGraphQl/Model/Resolver/StoreConfig.php | 10 +++++----- app/code/Magento/WeeeGraphQl/etc/schema.graphqls | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php index 58d2f54a670e..7aed6cb5d6a9 100644 --- a/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php +++ b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php @@ -24,16 +24,16 @@ class StoreConfig implements ResolverInterface /** * @var string */ - private static $weeeDisplaySettingsNone = 'NONE'; + private static $weeeDisplaySettingsNone = 'FPT_DISABLED'; /** * @var array */ private static $weeeDisplaySettings = [ - WeeeDisplayConfig::DISPLAY_INCL => 'INCLUDING_FPT', - WeeeDisplayConfig::DISPLAY_INCL_DESCR => 'INCLUDING_FPT_AND_FPT_DESCRIPTION', - WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL => 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', - WeeeDisplayConfig::DISPLAY_EXCL => 'EXCLUDING_FPT' + WeeeDisplayConfig::DISPLAY_INCL => 'INCLUDE_FPT_WITHOUT_DETAILS', + WeeeDisplayConfig::DISPLAY_INCL_DESCR => 'INCLUDE_FPT_WITH_DETAILS', + WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL => 'EXCLUDE_FPT_WITH_DETAILS', + WeeeDisplayConfig::DISPLAY_EXCL => 'EXCLUDE_FPT_WITHOUT_DETAILS' ]; /** diff --git a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls index 0a24063c3513..161d335533ed 100644 --- a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls @@ -16,15 +16,15 @@ type FixedProductTax @doc(description: "A single FPT that can be applied to a pr } type StoreConfig { - product_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The product page display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") - category_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The category page display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") - sales_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "The sales modules pages display setting for the fixed product tax") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + product_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the **Display Prices On Product View Page** field. It indicates how FPT information is displayed on product pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + category_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the **Display Prices In Product Lists** field. It indicates how FPT information is displayed on category pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + sales_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the **Display Prices In Sales Modules** field. It indicates how FPT information is displayed on cart, checkout, and order pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") } enum FixedProductTaxDisplaySettings @doc(description: "This enumeration display settings for the fixed product tax") { - INCLUDING_FPT @doc(description: "Fixed product tax amount(s) is included into the price and details from fixed_product_taxes should not be displayed") - INCLUDING_FPT_AND_FPT_DESCRIPTION @doc(description: "Fixed product tax amount(s) is included into the price and the details from fixed_product_taxes should be displayed") - EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION @doc(description: "Fixed product tax amount(s) is included into the price and the details from fixed_product_taxes should be shown, also price without the amount(s) of fixed_product_taxes should be displayed") - EXCLUDING_FPT @doc(description: "Fixed product tax amount(s) is excluded from the price and details from fixed_product_taxes should not be displayed") - NONE @doc(description: "Fixed product tax feature is disabled and we should not show or query fixed_product_taxes field") + INCLUDE_FPT_WITHOUT_DETAILS @doc(description: "The displayed price includes the FPT amount without displaying the ProductPrice.fixed_product_taxes values. This value corresponds to **Including FPT only**") + INCLUDE_FPT_WITH_DETAILS @doc(description: "The displayed price includes the FPT amount while displaying the values of ProductPrice.fixed_product_taxes separately. This value corresponds to **Including FPT and FPT description**") + EXCLUDE_FPT_WITH_DETAILS @doc(description: "The displayed price does not include the FPT amount. The values of ProductPrice.fixed_product_taxes are displayed separately. This value corresponds to **Excluding FPT, Including FPT description and final price**") + EXCLUDE_FPT_WITHOUT_DETAILS @doc(description: "The displayed price does not include the FPT amount. The values from ProductPrice.fixed_product_taxes are not displayed. This value corresponds to **Excluding FPT**") + FPT_DISABLED @doc(description: "The FPT feature is not enabled. You can omit ProductPrice.fixed_product_taxes from your query") } From 19f354c97b970c8528ae214d2569175f677cfbe7 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 14 Oct 2019 11:40:49 -0500 Subject: [PATCH 56/61] MC-21491: Pricing :: FPT display settings - fix test --- .../CatalogUrlRewrite/UrlResolverTest.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index 8ee0c7c584c6..81df7cf2b7e1 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -68,7 +68,7 @@ public function testProductUrlResolver() $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $urlPath, $relativePath, @@ -117,7 +117,7 @@ public function testProductUrlWithNonSeoFriendlyUrlInput() $expectedType = $actualUrls->getEntityType(); $nonSeoFriendlyPath = $actualUrls->getTargetPath(); - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $nonSeoFriendlyPath, $relativePath, @@ -168,7 +168,7 @@ public function testRedirectsAndCustomInput() ] ); // querying the end redirect gives the same record - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $renamedKey . $suffix, $actualUrls->getRequestPath(), @@ -176,7 +176,7 @@ public function testRedirectsAndCustomInput() ); // querying a url that's a redirect the active redirected final url - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $productSku . $suffix, $actualUrls->getRequestPath(), @@ -205,7 +205,7 @@ public function testRedirectsAndCustomInput() $urlRewriteModel->save(); // querying a custom url that should return the target entity but relative should be the custom url - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $customUrl, $customUrl, @@ -220,7 +220,7 @@ public function testRedirectsAndCustomInput() ObjectManager::getInstance()->get(\Magento\TestFramework\Helper\CacheCleaner::class)->cleanAll(); //modifying query by adding spaces to avoid getting cached values. - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $customUrl, $actualUrls->getRequestPath(), @@ -267,7 +267,7 @@ public function testCategoryUrlResolver() $response = $this->graphQlQuery($query); $urlPath = $response['category']['url_key'] . $response['category']['url_suffix']; - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $categoryId, $urlPath, $relativePath, @@ -317,7 +317,7 @@ public function testProductUrlRewriteResolver() $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $urlPath, $relativePath, @@ -401,7 +401,7 @@ public function testCategoryUrlWithLeadingSlash() $response = $this->graphQlQuery($query); $urlPath = $response['category']['url_key'] . $response['category']['url_suffix']; - $this->assertResponseFromGraphQl( + $this->queryUrlAndAssertResponse( (int) $categoryId, $urlPath, $relativePath, @@ -455,7 +455,7 @@ public function testGetNonExistentUrlRewrite() * @param string $relativePath * @param string $expectedType */ - private function assertResponseFromGraphQl( + private function queryUrlAndAssertResponse( int $productId, string $urlKey, string $relativePath, From 4aace8c8a24db3f93abc2f2a78ecdf13b98f70b3 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 14 Oct 2019 13:02:19 -0500 Subject: [PATCH 57/61] MC-20158: Redirects are not supported in urlResolver - fix static --- app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php index bd728863b51e..39f9684f415a 100644 --- a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php +++ b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php @@ -75,7 +75,6 @@ public function resolve( 'type' => $this->sanitizeType($finalUrlRewrite->getEntityType()) ]; - if (empty($resultArray['id'])) { throw new GraphQlNoSuchEntityException( __('No such entity found with matching URL key: %url', ['url' => $url]) From 716a8b36085cd3b739b51f24e6a626f52dc41a28 Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Mon, 14 Oct 2019 13:43:49 -0500 Subject: [PATCH 58/61] MC-21491: Pricing :: FPT display settings - resolve docs --- .../WeeeGraphQl/Model/Resolver/StoreConfig.php | 2 +- app/code/Magento/WeeeGraphQl/etc/schema.graphqls | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php index 7aed6cb5d6a9..d2ea44fff5bc 100644 --- a/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php +++ b/app/code/Magento/WeeeGraphQl/Model/Resolver/StoreConfig.php @@ -32,7 +32,7 @@ class StoreConfig implements ResolverInterface private static $weeeDisplaySettings = [ WeeeDisplayConfig::DISPLAY_INCL => 'INCLUDE_FPT_WITHOUT_DETAILS', WeeeDisplayConfig::DISPLAY_INCL_DESCR => 'INCLUDE_FPT_WITH_DETAILS', - WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL => 'EXCLUDE_FPT_WITH_DETAILS', + WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL => 'EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS', WeeeDisplayConfig::DISPLAY_EXCL => 'EXCLUDE_FPT_WITHOUT_DETAILS' ]; diff --git a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls index 161d335533ed..18b0e7c1823e 100644 --- a/app/code/Magento/WeeeGraphQl/etc/schema.graphqls +++ b/app/code/Magento/WeeeGraphQl/etc/schema.graphqls @@ -16,15 +16,15 @@ type FixedProductTax @doc(description: "A single FPT that can be applied to a pr } type StoreConfig { - product_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the **Display Prices On Product View Page** field. It indicates how FPT information is displayed on product pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") - category_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the **Display Prices In Product Lists** field. It indicates how FPT information is displayed on category pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") - sales_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the **Display Prices In Sales Modules** field. It indicates how FPT information is displayed on cart, checkout, and order pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + product_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the 'Display Prices On Product View Page' field. It indicates how FPT information is displayed on product pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + category_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the 'Display Prices In Product Lists' field. It indicates how FPT information is displayed on category pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") + sales_fixed_product_tax_display_setting : FixedProductTaxDisplaySettings @doc(description: "Corresponds to the 'Display Prices In Sales Modules' field. It indicates how FPT information is displayed on cart, checkout, and order pages") @resolver(class: "Magento\\WeeeGraphQl\\Model\\Resolver\\StoreConfig") } enum FixedProductTaxDisplaySettings @doc(description: "This enumeration display settings for the fixed product tax") { - INCLUDE_FPT_WITHOUT_DETAILS @doc(description: "The displayed price includes the FPT amount without displaying the ProductPrice.fixed_product_taxes values. This value corresponds to **Including FPT only**") - INCLUDE_FPT_WITH_DETAILS @doc(description: "The displayed price includes the FPT amount while displaying the values of ProductPrice.fixed_product_taxes separately. This value corresponds to **Including FPT and FPT description**") - EXCLUDE_FPT_WITH_DETAILS @doc(description: "The displayed price does not include the FPT amount. The values of ProductPrice.fixed_product_taxes are displayed separately. This value corresponds to **Excluding FPT, Including FPT description and final price**") - EXCLUDE_FPT_WITHOUT_DETAILS @doc(description: "The displayed price does not include the FPT amount. The values from ProductPrice.fixed_product_taxes are not displayed. This value corresponds to **Excluding FPT**") + INCLUDE_FPT_WITHOUT_DETAILS @doc(description: "The displayed price includes the FPT amount without displaying the ProductPrice.fixed_product_taxes values. This value corresponds to 'Including FPT only'") + INCLUDE_FPT_WITH_DETAILS @doc(description: "The displayed price includes the FPT amount while displaying the values of ProductPrice.fixed_product_taxes separately. This value corresponds to 'Including FPT and FPT description'") + EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS @doc(description: "The displayed price does not include the FPT amount. The values of ProductPrice.fixed_product_taxes and the price including the FPT are displayed separately. This value corresponds to 'Excluding FPT, Including FPT description and final price'") + EXCLUDE_FPT_WITHOUT_DETAILS @doc(description: "The displayed price does not include the FPT amount. The values from ProductPrice.fixed_product_taxes are not displayed. This value corresponds to 'Excluding FPT'") FPT_DISABLED @doc(description: "The FPT feature is not enabled. You can omit ProductPrice.fixed_product_taxes from your query") } From fa04a640f0618627b75c4f4b6d7125c6cb9f8abc Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Tue, 15 Oct 2019 14:09:23 -0500 Subject: [PATCH 59/61] MC-20158: Redirects are not supported in urlResolver - add redirect code --- .../Model/Resolver/EntityUrl.php | 18 ++++++++++++++---- .../UrlRewriteGraphQl/etc/schema.graphqls | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php index 39f9684f415a..e6b03755bea4 100644 --- a/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php +++ b/app/code/Magento/UrlRewriteGraphQl/Model/Resolver/EntityUrl.php @@ -31,6 +31,11 @@ class EntityUrl implements ResolverInterface */ private $customUrlLocator; + /** + * @var int + */ + private $redirectType; + /** * @param UrlFinderInterface $urlFinder * @param CustomUrlLocatorInterface $customUrlLocator @@ -63,6 +68,7 @@ public function resolve( if (substr($url, 0, 1) === '/' && $url !== '/') { $url = ltrim($url, '/'); } + $this->redirectType = 0; $customUrl = $this->customUrlLocator->locateUrl($url); $url = $customUrl ?: $url; $finalUrlRewrite = $this->findFinalUrl($url, $storeId); @@ -72,6 +78,7 @@ public function resolve( 'id' => $finalUrlRewrite->getEntityId(), 'canonical_url' => $relativeUrl, 'relative_url' => $relativeUrl, + 'redirectCode' => $this->redirectType, 'type' => $this->sanitizeType($finalUrlRewrite->getEntityType()) ]; @@ -105,6 +112,7 @@ private function rewriteCustomUrls(UrlRewrite $finalUrlRewrite, int $storeId): ? 'id' => $finalUrlRewrite->getEntityId(), 'canonical_url' => $relativeUrl, 'relative_url' => $relativeUrl, + 'redirectCode' => $finalCustomUrlRewrite->getRedirectType(), 'type' => $this->sanitizeType($finalUrlRewrite->getEntityType()) ]; } @@ -122,10 +130,12 @@ private function rewriteCustomUrls(UrlRewrite $finalUrlRewrite, int $storeId): ? private function findFinalUrl(string $requestPath, int $storeId, bool $findCustom = false): ?UrlRewrite { $urlRewrite = $this->findUrlFromRequestPath($requestPath, $storeId); - while ($urlRewrite && $urlRewrite->getRedirectType() > 0) { - $urlRewrite = $this->findUrlFromRequestPath($urlRewrite->getTargetPath(), $storeId); - } - if (!$urlRewrite) { + if ($urlRewrite) { + $this->redirectType = $urlRewrite->getRedirectType(); + while ($urlRewrite && $urlRewrite->getRedirectType() > 0) { + $urlRewrite = $this->findUrlFromRequestPath($urlRewrite->getTargetPath(), $storeId); + } + } else { $urlRewrite = $this->findUrlFromTargetPath($requestPath, $storeId); } if ($urlRewrite && ($findCustom && !$urlRewrite->getEntityId() && !$urlRewrite->getIsAutogenerated())) { diff --git a/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls b/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls index ace3e0eae831..7f7ebb627b4d 100644 --- a/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/UrlRewriteGraphQl/etc/schema.graphqls @@ -9,6 +9,7 @@ type EntityUrl @doc(description: "EntityUrl is an output object containing the ` id: Int @doc(description: "The ID assigned to the object associated with the specified url. This could be a product ID, category ID, or page ID.") canonical_url: String @deprecated(reason: "The canonical_url field is deprecated, use relative_url instead.") relative_url: String @doc(description: "The internal relative URL. If the specified url is a redirect, the query returns the redirected URL, not the original.") + redirectCode: Int @doc(description: "301 or 302 HTTP code for url permanent or temporary redirect or 0 for the 200 no redirect") type: UrlRewriteEntityTypeEnum @doc(description: "One of PRODUCT, CATEGORY, or CMS_PAGE.") } From c5e8a15f6334a5596f7e8c865d8bab05933f4980 Mon Sep 17 00:00:00 2001 From: Deepty Thampy <dthampy@adobe.com> Date: Tue, 15 Oct 2019 16:45:43 -0500 Subject: [PATCH 60/61] MC-20158: [GraphQL] Redirects are not supported in urlResolver - added few validations for redirectType --- .../CatalogUrlRewrite/UrlResolverTest.php | 42 +++++++++++++------ .../GraphQl/CmsUrlRewrite/UrlResolverTest.php | 6 +++ .../GraphQl/UrlRewrite/UrlResolverTest.php | 1 + 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php index 81df7cf2b7e1..29696e29908f 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CatalogUrlRewrite/UrlResolverTest.php @@ -67,12 +67,14 @@ public function testProductUrlResolver() ); $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); + $redirectCode = $actualUrls->getRedirectType(); $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $urlPath, $relativePath, - $expectedType + $expectedType, + $redirectCode ); } @@ -116,12 +118,14 @@ public function testProductUrlWithNonSeoFriendlyUrlInput() $relativePath = $actualUrls->getRequestPath(); $expectedType = $actualUrls->getEntityType(); $nonSeoFriendlyPath = $actualUrls->getTargetPath(); + $redirectCode = $actualUrls->getRedirectType(); $this->queryUrlAndAssertResponse( (int) $product->getEntityId(), $nonSeoFriendlyPath, $relativePath, - $expectedType + $expectedType, + $redirectCode ); } @@ -172,7 +176,8 @@ public function testRedirectsAndCustomInput() (int) $product->getEntityId(), $renamedKey . $suffix, $actualUrls->getRequestPath(), - $actualUrls->getEntityType() + $actualUrls->getEntityType(), + 0 ); // querying a url that's a redirect the active redirected final url @@ -180,7 +185,8 @@ public function testRedirectsAndCustomInput() (int) $product->getEntityId(), $productSku . $suffix, $actualUrls->getRequestPath(), - $actualUrls->getEntityType() + $actualUrls->getEntityType(), + 301 ); // create custom url that doesn't redirect @@ -209,7 +215,8 @@ public function testRedirectsAndCustomInput() (int) $product->getEntityId(), $customUrl, $customUrl, - $actualUrls->getEntityType() + $actualUrls->getEntityType(), + 0 ); // change custom url that does redirect @@ -224,7 +231,8 @@ public function testRedirectsAndCustomInput() (int) $product->getEntityId(), $customUrl, $actualUrls->getRequestPath(), - strtoupper($actualUrls->getEntityType()) + strtoupper($actualUrls->getEntityType()), + 301 ); $urlRewriteModel->delete(); } @@ -271,7 +279,8 @@ public function testCategoryUrlResolver() (int) $categoryId, $urlPath, $relativePath, - $expectedType + $expectedType, + 0 ); } @@ -321,7 +330,8 @@ public function testProductUrlRewriteResolver() (int) $product->getEntityId(), $urlPath, $relativePath, - $expectedType + $expectedType, + 0 ); } @@ -355,6 +365,7 @@ public function testInvalidUrlResolverInput() id relative_url type + redirectCode } } QUERY; @@ -400,12 +411,13 @@ public function testCategoryUrlWithLeadingSlash() QUERY; $response = $this->graphQlQuery($query); $urlPath = $response['category']['url_key'] . $response['category']['url_suffix']; - + $urlPathWithLeadingSlash = "/{$urlPath}"; $this->queryUrlAndAssertResponse( (int) $categoryId, - $urlPath, + $urlPathWithLeadingSlash, $relativePath, - $expectedType + $expectedType, + 0 ); } @@ -438,6 +450,7 @@ public function testGetNonExistentUrlRewrite() id relative_url type + redirectCode } } QUERY; @@ -445,6 +458,7 @@ public function testGetNonExistentUrlRewrite() $this->assertArrayHasKey('urlResolver', $response); $this->assertEquals('PRODUCT', $response['urlResolver']['type']); $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); + $this->assertEquals(0, $response['urlResolver']['redirectCode']); } /** @@ -454,12 +468,14 @@ public function testGetNonExistentUrlRewrite() * @param string $urlKey * @param string $relativePath * @param string $expectedType + * @param int $redirectCode */ private function queryUrlAndAssertResponse( int $productId, string $urlKey, string $relativePath, - string $expectedType + string $expectedType, + int $redirectCode ): void { $query = <<<QUERY @@ -469,6 +485,7 @@ private function queryUrlAndAssertResponse( id relative_url type + redirectCode } } QUERY; @@ -477,5 +494,6 @@ private function queryUrlAndAssertResponse( $this->assertEquals($productId, $response['urlResolver']['id']); $this->assertEquals($relativePath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper($expectedType), $response['urlResolver']['type']); + $this->assertEquals($redirectCode, $response['urlResolver']['redirectCode']); } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php index de165ca39159..072c6bc38de7 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/CmsUrlRewrite/UrlResolverTest.php @@ -53,6 +53,7 @@ public function testCMSPageUrlResolver() id relative_url type + redirectCode } } QUERY; @@ -60,6 +61,7 @@ public function testCMSPageUrlResolver() $this->assertEquals($cmsPageId, $response['urlResolver']['id']); $this->assertEquals($requestPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper(str_replace('-', '_', $expectedEntityType)), $response['urlResolver']['type']); + $this->assertEquals(0, $response['urlResolver']['redirectCode']); // querying by non seo friendly url path should return seo friendly relative url $query @@ -70,6 +72,7 @@ public function testCMSPageUrlResolver() id relative_url type + redirectCode } } QUERY; @@ -77,6 +80,7 @@ public function testCMSPageUrlResolver() $this->assertEquals($cmsPageId, $response['urlResolver']['id']); $this->assertEquals($requestPath, $response['urlResolver']['relative_url']); $this->assertEquals(strtoupper(str_replace('-', '_', $expectedEntityType)), $response['urlResolver']['type']); + $this->assertEquals(0, $response['urlResolver']['redirectCode']); } /** @@ -102,6 +106,7 @@ public function testResolveSlash() id relative_url type + redirectCode } } QUERY; @@ -110,5 +115,6 @@ public function testResolveSlash() $this->assertEquals($homePageId, $response['urlResolver']['id']); $this->assertEquals($homePageIdentifier, $response['urlResolver']['relative_url']); $this->assertEquals('CMS_PAGE', $response['urlResolver']['type']); + $this->assertEquals(0, $response['urlResolver']['redirectCode']); } } diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php index bd20741fb741..5e6415f82b25 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/UrlRewrite/UrlResolverTest.php @@ -39,6 +39,7 @@ public function testNonExistentEntityUrlRewrite() id relative_url type + redirectCode } } QUERY; From 4450619cba3459e9c3605fb41f7034f608ea7cfc Mon Sep 17 00:00:00 2001 From: Cristian Partica <cpartica@magento.com> Date: Tue, 15 Oct 2019 16:53:57 -0500 Subject: [PATCH 61/61] MC-21491: Pricing :: FPT display settings - fix tests --- .../Magento/GraphQl/Tax/ProductViewTest.php | 1 - .../GraphQl/Weee/StoreConfigFPTTest.php | 19 +++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php index 2f33d3f46a10..1dc5a813de2b 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Tax/ProductViewTest.php @@ -41,7 +41,6 @@ class ProductViewTest extends GraphQlAbstract /** @var string */ private $defaultRegionSystemSetting; - /** @var string */ private $defaultPriceDisplayType; diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php index f7a332c22d3c..451ea78ee308 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Weee/StoreConfigFPTTest.php @@ -81,7 +81,7 @@ public function sameFPTDisplaySettingsProvider() Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL, Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL, ], - 'displayValue' => 'INCLUDING_FPT', + 'displayValue' => 'INCLUDE_FPT_WITHOUT_DETAILS', ], [ 'weeTaxSettingsDisplayIncludedAndDescription' => [ @@ -90,7 +90,7 @@ public function sameFPTDisplaySettingsProvider() Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_INCL_DESCR, Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_INCL_DESCR, ], - 'displayValue' => 'INCLUDING_FPT_AND_FPT_DESCRIPTION', + 'displayValue' => 'INCLUDE_FPT_WITH_DETAILS', ], [ 'weeTaxSettingsDisplayIncludedAndExcludedAndDescription' => [ @@ -99,7 +99,7 @@ public function sameFPTDisplaySettingsProvider() Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL_DESCR_INCL, ], - 'displayValue' => 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', + 'displayValue' => 'EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS', ], [ 'weeTaxSettingsDisplayExcluded' => [ @@ -108,7 +108,7 @@ public function sameFPTDisplaySettingsProvider() Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, ], - 'displayValue' => 'EXCLUDING_FPT', + 'displayValue' => 'EXCLUDE_FPT_WITHOUT_DETAILS', ], [ 'weeTaxSettingsDisplayExcluded' => [ @@ -117,7 +117,7 @@ public function sameFPTDisplaySettingsProvider() Config::XML_PATH_FPT_DISPLAY_PRODUCT_LIST => WeeeDisplayConfig::DISPLAY_EXCL, Config::XML_PATH_FPT_DISPLAY_SALES => WeeeDisplayConfig::DISPLAY_EXCL, ], - 'displayValue' => 'NONE', + 'displayValue' => 'FPT_DISABLED', ], ]; } @@ -151,13 +151,16 @@ public function testDifferentFPTDisplaySettings(array $weeTaxSettings) $this->assertNotEmpty($result['storeConfig']['category_fixed_product_tax_display_setting']); $this->assertNotEmpty($result['storeConfig']['sales_fixed_product_tax_display_setting']); - $this->assertEquals('INCLUDING_FPT', $result['storeConfig']['product_fixed_product_tax_display_setting']); $this->assertEquals( - 'INCLUDING_FPT_AND_FPT_DESCRIPTION', + 'INCLUDE_FPT_WITHOUT_DETAILS', + $result['storeConfig']['product_fixed_product_tax_display_setting'] + ); + $this->assertEquals( + 'INCLUDE_FPT_WITH_DETAILS', $result['storeConfig']['category_fixed_product_tax_display_setting'] ); $this->assertEquals( - 'EXCLUDING_FPT_INCLUDING_FPT_AND_FPT_DESCRIPTION', + 'EXCLUDE_FPT_AND_INCLUDE_WITH_DETAILS', $result['storeConfig']['sales_fixed_product_tax_display_setting'] ); }