From 04bc0fb4f05772b61f7345bbc36fc304eba0e744 Mon Sep 17 00:00:00 2001 From: LisovyiEvhenii Date: Sat, 10 Nov 2018 11:44:19 +0200 Subject: [PATCH 01/88] Add availability to leave empty config for events.xml --- lib/internal/Magento/Framework/Event/etc/events.xsd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Event/etc/events.xsd b/lib/internal/Magento/Framework/Event/etc/events.xsd index d656b7fdb6ed6..cac62af356760 100644 --- a/lib/internal/Magento/Framework/Event/etc/events.xsd +++ b/lib/internal/Magento/Framework/Event/etc/events.xsd @@ -9,7 +9,7 @@ - + From 551a2681cdaca079882e019cceeb78fa0387f919 Mon Sep 17 00:00:00 2001 From: LisovyiEvhenii Date: Sun, 11 Nov 2018 11:52:41 +0200 Subject: [PATCH 02/88] Fix unit test of Framework/Event module --- .../Event/Test/Unit/Config/_files/invalidEventsXmlArray.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php index 33007b7295bca..e0dc7494cca19 100644 --- a/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php +++ b/lib/internal/Magento/Framework/Event/Test/Unit/Config/_files/invalidEventsXmlArray.php @@ -4,10 +4,6 @@ * See COPYING.txt for license details. */ return [ - 'without_event_handle' => [ - '', - ["Element 'config': Missing child element(s). Expected is ( event ).\nLine: 1\n"], - ], 'event_without_required_name_attribute' => [ '', ["Element 'event': Missing child element(s). Expected is ( observer ).\nLine: 1\n"], From f761ee9dd8d58c435e8abf1b09fe67f7d780c66f Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun Date: Tue, 13 Nov 2018 09:15:57 +0200 Subject: [PATCH 03/88] MAGETWO-96141: "Custom price" can't be removed during order creation in admin --- .../Quote/Model/Quote/Item/Updater.php | 4 +- .../Unit/Model/Quote/Item/UpdaterTest.php | 10 ++- .../Quote/Model/Quote/Item/UpdaterTest.php | 60 +++++++++++++++ .../Sales/_files/quote_with_custom_price.php | 74 +++++++++++++++++++ .../quote_with_custom_price_rollback.php | 6 ++ 5 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php diff --git a/app/code/Magento/Quote/Model/Quote/Item/Updater.php b/app/code/Magento/Quote/Model/Quote/Item/Updater.php index 6a7a3c1c1839e..05244d4ecc43a 100644 --- a/app/code/Magento/Quote/Model/Quote/Item/Updater.php +++ b/app/code/Magento/Quote/Model/Quote/Item/Updater.php @@ -145,8 +145,8 @@ protected function unsetCustomPrice(Item $item) $item->addOption($infoBuyRequest); } - $item->unsetData('custom_price'); - $item->unsetData('original_custom_price'); + $item->setData('custom_price', null); + $item->setData('original_custom_price', null); } /** diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php index 7933da7c5fe37..8e6a3723caa7c 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/UpdaterTest.php @@ -67,7 +67,7 @@ protected function setUp() 'addOption', 'setCustomPrice', 'setOriginalCustomPrice', - 'unsetData', + 'setData', 'hasData', 'setIsQtyDecimal' ]); @@ -301,7 +301,7 @@ public function testUpdateUnsetCustomPrice() 'setProduct', 'getData', 'unsetData', - 'hasData' + 'hasData', ]); $buyRequestMock->expects($this->never())->method('setCustomPrice'); $buyRequestMock->expects($this->once())->method('getData')->will($this->returnValue([])); @@ -353,7 +353,11 @@ public function testUpdateUnsetCustomPrice() ->will($this->returnValue($buyRequestMock)); $this->itemMock->expects($this->exactly(2)) - ->method('unsetData'); + ->method('setData') + ->withConsecutive( + ['custom_price', null], + ['original_custom_price', null] + ); $this->itemMock->expects($this->once()) ->method('hasData') diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php new file mode 100644 index 0000000000000..4d5fd0b54061a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php @@ -0,0 +1,60 @@ +updater = Bootstrap::getObjectManager()->create(Updater::class); + } + + /** + * @magentoDataFixture Magento/Sales/_files/quote_with_custom_price.php + * @return void + */ + public function testUpdate() + { + /** @var CartItemRepositoryInterface $quoteItemRepository */ + $quoteItemRepository = Bootstrap::getObjectManager()->create(CartItemRepositoryInterface::class); + /** @var Quote $quote */ + $quote = Bootstrap::getObjectManager()->create(Quote::class); + $quoteId = $quote->load('test01', 'reserved_order_id')->getId(); + /** @var CartItemInterface[] $quoteItems */ + $quoteItems = $quoteItemRepository->getList($quoteId); + /** @var CartItemInterface $actualQuoteItem */ + $actualQuoteItem = array_pop($quoteItems); + $this->assertInstanceOf(CartItemInterface::class, $actualQuoteItem); + + $info = [ + 'qty' => 1, + ]; + $this->updater->update($actualQuoteItem, $info); + + $this->assertNull( + $actualQuoteItem->getCustomPrice(), + 'Item custom price has to be null' + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php new file mode 100644 index 0000000000000..b3dc0fea79d6b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php @@ -0,0 +1,74 @@ +loadArea('frontend'); +$product = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId('simple') + ->setId(1) + ->setAttributeSetId(4) + ->setName('Simple Product') + ->setSku('simple') + ->setPrice(10) + ->setTaxClassId(0) + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData( + [ + 'qty' => 100, + 'is_in_stock' => 1, + ] + )->save(); + +$productRepository = Bootstrap::getObjectManager()->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$product = $productRepository->get('simple'); + +$addressData = include __DIR__ . '/address_data.php'; +$billingAddress = Bootstrap::getObjectManager()->create( + \Magento\Quote\Model\Quote\Address::class, + ['data' => $addressData] +); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); + +$store = Bootstrap::getObjectManager() + ->get(\Magento\Store\Model\StoreManagerInterface::class) + ->getStore(); + +$requestData = [ + 'qty' => 1, + 'custom_price' => 12, +]; +$request = Bootstrap::getObjectManager()->create(\Magento\Framework\DataObject::class, ['data' => $requestData]); + +/** @var \Magento\Quote\Model\Quote $quote */ +$quote = Bootstrap::getObjectManager()->create(\Magento\Quote\Model\Quote::class); +$quote->setCustomerIsGuest(true) + ->setStoreId($store->getId()) + ->setReservedOrderId('test01') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->addProduct($product, $request); +$quote->getPayment()->setMethod('checkmo'); +$quote->setIsMultiShipping('1'); +$quote->collectTotals(); + +$quoteRepository = Bootstrap::getObjectManager()->create(\Magento\Quote\Api\CartRepositoryInterface::class); +$quoteRepository->save($quote); + +/** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ +$quoteIdMask = Bootstrap::getObjectManager() + ->create(\Magento\Quote\Model\QuoteIdMaskFactory::class) + ->create(); +$quoteIdMask->setQuoteId($quote->getId()); +$quoteIdMask->setDataChanges(true); +$quoteIdMask->save(); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php new file mode 100644 index 0000000000000..ccfd4a0768709 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php @@ -0,0 +1,6 @@ + Date: Tue, 13 Nov 2018 09:45:10 +0200 Subject: [PATCH 04/88] MAGETWO-96141: "Custom price" can't be removed during order creation in admin --- .../testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php index 4d5fd0b54061a..137d3347653bc 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/Item/UpdaterTest.php @@ -55,6 +55,6 @@ public function testUpdate() $this->assertNull( $actualQuoteItem->getCustomPrice(), 'Item custom price has to be null' - ); + ); } } From da4b10f56a475fc0711b8ec2a0ccc2571881c42b Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun Date: Wed, 14 Nov 2018 11:57:21 +0200 Subject: [PATCH 05/88] MAGETWO-96141: "Custom price" can't be removed during order creation in admin --- .../Magento/Sales/_files/quote_with_custom_price.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php index b3dc0fea79d6b..3ed44bfd69528 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price.php @@ -9,10 +9,9 @@ Bootstrap::getInstance()->loadArea('frontend'); $product = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class); $product->setTypeId('simple') - ->setId(1) ->setAttributeSetId(4) ->setName('Simple Product') - ->setSku('simple') + ->setSku('simple_quote_custom_price') ->setPrice(10) ->setTaxClassId(0) ->setMetaTitle('meta title') @@ -28,7 +27,7 @@ )->save(); $productRepository = Bootstrap::getObjectManager()->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); -$product = $productRepository->get('simple'); +$product = $productRepository->get('simple_quote_custom_price'); $addressData = include __DIR__ . '/address_data.php'; $billingAddress = Bootstrap::getObjectManager()->create( From ab0223b8c50c65e8c025caacd579949b9aba5f4a Mon Sep 17 00:00:00 2001 From: DianaRusin Date: Mon, 19 Nov 2018 13:15:33 +0200 Subject: [PATCH 06/88] MAGETWO-89438: Advanced pricing the bulk discounts by percentage returns error when set --- .../Product/Form/Modifier/TierPrice.php | 11 +++++++---- .../view/base/web/js/lib/validation/rules.js | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php index 0eddca3322205..1a9b9f205d701 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php @@ -45,7 +45,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc * @since 101.1.0 */ public function modifyData(array $data) @@ -54,8 +54,11 @@ public function modifyData(array $data) } /** - * {@inheritdoc} + * Add tier price info to meta array. + * * @since 101.1.0 + * @param array $meta + * @return array */ public function modifyMeta(array $meta) { @@ -150,8 +153,8 @@ private function getUpdatedTierPriceStructure(array $priceMeta) 'dataType' => Price::NAME, 'addbefore' => '%', 'validation' => [ - 'validate-number' => true, - 'less-than-equals-to' => 100 + 'required-entry' => true, + 'validate-positive-percent-decimal' => true, ], 'visible' => $firstOption && $firstOption['value'] == ProductPriceOptionsInterface::VALUE_PERCENT, diff --git a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js index 8e59f9d290906..cbfc0dae90dda 100644 --- a/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js +++ b/app/code/Magento/Ui/view/base/web/js/lib/validation/rules.js @@ -691,6 +691,24 @@ define([ }, $.mage.__('The value is not within the specified range.') ], + 'validate-positive-percent-decimal': [ + function (value) { + var numValue; + + if (utils.isEmptyNoTrim(value) || !/^\s*-?\d*(\.\d*)?\s*$/.test(value)) { + return false; + } + + numValue = utils.parseNumber(value); + + if (isNaN(numValue)) { + return false; + } + + return utils.isBetween(numValue, 0.01, 100); + }, + $.mage.__('Please enter a valid percentage discount value greater than 0.') + ], 'validate-digits': [ function (value) { return utils.isEmptyNoTrim(value) || !/[^\d]/.test(value); From 8a9e678ecd7ffc1e0a7ca26c9dd78ed85aed8c62 Mon Sep 17 00:00:00 2001 From: DianaRusin Date: Tue, 20 Nov 2018 16:43:42 +0200 Subject: [PATCH 07/88] MAGETWO-89438: Advanced pricing the bulk discounts by percentage returns error when set --- ...AdminProductFormAdvancedPricingSection.xml | 1 + ...pplyingTierPriceWithEmptyDiscountValue.xml | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml index 0f1fe8abeb3b5..ef66a41e27d06 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFormAdvancedPricingSection.xml @@ -18,6 +18,7 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml new file mode 100644 index 0000000000000..60f950faaebce --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml @@ -0,0 +1,57 @@ + + + + + + + + + <description value="Validate applying tier price to product"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-96484"/> + <group value="product"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + <field key="price">100</field> + </createData> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad time="30" stepKey="waitForProductIndexPageLoad"/> + <actionGroup ref="AdminResetProductGridToDefaultViewActionGroup" stepKey="resetGridToDefaultKeywordSearch"/> + <actionGroup ref="logout" stepKey="logoutFromAdmin"/> + </after> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="searchForSimpleProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProductPage"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + <waitForPageLoad stepKey="waitForProductPage"/> + <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton"/> + <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForCustomerGroupPriceAddButton"/> + <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="addCustomerGroupPrice"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPriceQtyInput('0')}}" userInput="1" stepKey="fillProductTierPriceQtyInput"/> + <selectOption selector="{{AdminProductFormAdvancedPricingSection.productTierPriceValueTypeSelect('0')}}" userInput="Discount" stepKey="selectProductTierPriceValueType"/> + <clearField selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('0')}}" stepKey="clearPercentageValueField"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton"/> + <see selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageError}}" userInput="This is a required field." stepKey="assertPercentageError"/> + <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('0')}}" userInput="10" stepKey="setPercentageValue"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton2"/> + <dontSee selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageError}}" userInput="This is a required field." stepKey="assertNoPercentageError"/> + <actionGroup ref="SaveProductOnProductPageOnAdmin" stepKey="saveProduct"/> + </test> +</tests> From d30ae920ac10b1382a66763a2e0222af4f5dd731 Mon Sep 17 00:00:00 2001 From: Stas Kozar <stas.kozar@transoftgroup.com> Date: Wed, 21 Nov 2018 14:12:53 +0200 Subject: [PATCH 08/88] MAGETWO-92576: Top menu should use cached version instead of rendering --- app/code/Magento/Theme/Block/Html/Topmenu.php | 13 ------------- .../Theme/Test/Unit/Block/Html/TopmenuTest.php | 3 +-- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/app/code/Magento/Theme/Block/Html/Topmenu.php b/app/code/Magento/Theme/Block/Html/Topmenu.php index 47f88c65acb80..2e643eadcf447 100644 --- a/app/code/Magento/Theme/Block/Html/Topmenu.php +++ b/app/code/Magento/Theme/Block/Html/Topmenu.php @@ -361,19 +361,6 @@ public function getIdentities() return $this->identities; } - /** - * Get cache key informative items - * - * @return array - * @since 100.1.0 - */ - public function getCacheKeyInfo() - { - $keyInfo = parent::getCacheKeyInfo(); - $keyInfo[] = $this->getUrl('*/*/*', ['_current' => true, '_query' => '']); - return $keyInfo; - } - /** * Get tags array for saving cache * diff --git a/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php b/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php index 91c3ce47fc8b8..023c741492752 100644 --- a/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php +++ b/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php @@ -189,7 +189,6 @@ public function testGetCacheKeyInfo() $treeFactory = $this->createMock(\Magento\Framework\Data\TreeFactory::class); $topmenu = new Topmenu($this->context, $nodeFactory, $treeFactory); - $this->urlBuilder->expects($this->once())->method('getUrl')->with('*/*/*')->willReturn('123'); $this->urlBuilder->expects($this->once())->method('getBaseUrl')->willReturn('baseUrl'); $store = $this->getMockBuilder(\Magento\Store\Model\Store::class) ->disableOriginalConstructor() @@ -199,7 +198,7 @@ public function testGetCacheKeyInfo() $this->storeManager->expects($this->once())->method('getStore')->willReturn($store); $this->assertEquals( - ['BLOCK_TPL', '321', null, 'base_url' => 'baseUrl', 'template' => null, '123'], + ['BLOCK_TPL', '321', null, 'base_url' => 'baseUrl', 'template' => null], $topmenu->getCacheKeyInfo() ); } From 95dd85747b89f34181509c89f2436f7370a677ab Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Thu, 22 Nov 2018 09:28:24 +0200 Subject: [PATCH 09/88] MAGETWO-89438: Advanced pricing the bulk discounts by percentage returns error when set --- .../AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml index 60f950faaebce..c634c3ee3ba83 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml @@ -6,8 +6,7 @@ */ --> -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="AdminValidateApplyingTierPriceWithEmptyDiscountValue"> <annotations> <features value="Apply tier price"/> From 03552821331c11c6cfe139983c76efcc26dbd635 Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Thu, 22 Nov 2018 09:32:05 +0200 Subject: [PATCH 10/88] MAGETWO-89438: Advanced pricing the bulk discounts by percentage returns error when set --- ...dminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename app/code/Magento/Catalog/Test/Mftf/Test/{AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml => AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml} (99%) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml similarity index 99% rename from app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml rename to app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml index c634c3ee3ba83..bf94971ee9e87 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValue.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml @@ -7,7 +7,7 @@ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="AdminValidateApplyingTierPriceWithEmptyDiscountValue"> + <test name="AdminValidateApplyingTierPriceWithEmptyDiscountValueTest"> <annotations> <features value="Apply tier price"/> <title value="Apply Tier Price with empty discount value"/> From 6a38c2820dc3e512573a11b83a158957863db790 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Thu, 22 Nov 2018 16:05:53 +0200 Subject: [PATCH 11/88] MAGETWO-86983: Reward Points Balance Update Emails are not being sent when balance change initiated by store front - Fixed an issue with incorrect work of 'Subscribe for Balance Updates' functionality - Fixed integration test - Fixed API test --- .../Model/Metadata/CustomerMetadata.php | 19 +++++++++++++++---- app/code/Magento/Customer/etc/di.xml | 7 +++++++ .../Customer/Api/CustomerMetadataTest.php | 14 ++++++++++++++ .../Customer/Model/CustomerMetadataTest.php | 19 +++++++++++++------ 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php b/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php index 7ed806e657e82..a9753fc810a99 100644 --- a/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php +++ b/app/code/Magento/Customer/Model/Metadata/CustomerMetadata.php @@ -33,16 +33,26 @@ class CustomerMetadata implements CustomerMetadataInterface */ private $attributeMetadataDataProvider; + /** + * List of system attributes which should be available to the clients. + * + * @var string[] + */ + private $systemAttributes; + /** * @param AttributeMetadataConverter $attributeMetadataConverter * @param AttributeMetadataDataProvider $attributeMetadataDataProvider + * @param string[] $systemAttributes */ public function __construct( AttributeMetadataConverter $attributeMetadataConverter, - AttributeMetadataDataProvider $attributeMetadataDataProvider + AttributeMetadataDataProvider $attributeMetadataDataProvider, + array $systemAttributes = [] ) { $this->attributeMetadataConverter = $attributeMetadataConverter; $this->attributeMetadataDataProvider = $attributeMetadataDataProvider; + $this->systemAttributes = $systemAttributes; } /** @@ -116,7 +126,7 @@ public function getAllAttributesMetadata() } /** - * {@inheritdoc} + * @inheritdoc */ public function getCustomAttributesMetadata($dataObjectClassName = self::DATA_INTERFACE_NAME) { @@ -134,9 +144,10 @@ public function getCustomAttributesMetadata($dataObjectClassName = self::DATA_IN $isDataObjectMethod = isset($this->customerDataObjectMethods['get' . $camelCaseKey]) || isset($this->customerDataObjectMethods['is' . $camelCaseKey]); - /** Even though disable_auto_group_change is system attribute, it should be available to the clients */ if (!$isDataObjectMethod - && (!$attributeMetadata->isSystem() || $attributeCode == 'disable_auto_group_change') + && (!$attributeMetadata->isSystem() + || in_array($attributeCode, $this->systemAttributes) + ) ) { $customAttributes[] = $attributeMetadata; } diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index fa7dd80882632..c6e383fb73bde 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -127,6 +127,13 @@ <argument name="groupManagement" xsi:type="object">Magento\Customer\Api\GroupManagementInterface\Proxy</argument> </arguments> </type> + <type name="Magento\Customer\Model\Metadata\CustomerMetadata"> + <arguments> + <argument name="systemAttributes" xsi:type="array"> + <item name="disable_auto_group_change" xsi:type="string">disable_auto_group_change</item> + </argument> + </arguments> + </type> <virtualType name="SectionInvalidationConfigReader" type="Magento\Framework\Config\Reader\Filesystem"> <arguments> <argument name="idAttributes" xsi:type="array"> diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php index f2632aa1481e4..61121de9cb336 100644 --- a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php @@ -9,6 +9,7 @@ use Magento\Customer\Api\Data\CustomerInterface as Customer; use Magento\Customer\Model\Data\AttributeMetadata; use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\TestFramework\Helper\Bootstrap; /** * Class CustomerMetadataTest @@ -19,6 +20,19 @@ class CustomerMetadataTest extends WebapiAbstract const SERVICE_VERSION = "V1"; const RESOURCE_PATH = "/V1/attributeMetadata/customer"; + /** + * @var CustomerMetadataInterface + */ + private $customerMetadata; + + /** + * @inheritdoc + */ + public function setUp() + { + $this->customerMetadata = Bootstrap::getObjectManager()->create(CustomerMetadataInterface::class); + } + /** * Test retrieval of attribute metadata for the customer entity type. * diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php index 5425af856bd9f..d013309eda3dc 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/CustomerMetadataTest.php @@ -54,16 +54,23 @@ protected function setUp() public function testGetCustomAttributesMetadata() { - $customAttributesMetadata = $this->service->getCustomAttributesMetadata(); - $this->assertCount(0, $customAttributesMetadata, "Invalid number of attributes returned."); + $customAttributesMetadataQty = count($this->service->getCustomAttributesMetadata()) ; // Verify the consistency of getCustomerAttributeMetadata() function from the 2nd call of the same service - $customAttributesMetadata1 = $this->service->getCustomAttributesMetadata(); - $this->assertCount(0, $customAttributesMetadata1, "Invalid number of attributes returned."); + $customAttributesMetadata1Qty = count($this->service->getCustomAttributesMetadata()); + $this->assertEquals( + $customAttributesMetadataQty, + $customAttributesMetadata1Qty, + "Invalid number of attributes returned." + ); // Verify the consistency of getCustomAttributesMetadata() function from the 2nd service - $customAttributesMetadata2 = $this->serviceTwo->getCustomAttributesMetadata(); - $this->assertCount(0, $customAttributesMetadata2, "Invalid number of attributes returned."); + $customAttributesMetadata2Qty = count($this->serviceTwo->getCustomAttributesMetadata()); + $this->assertEquals( + $customAttributesMetadataQty, + $customAttributesMetadata2Qty, + "Invalid number of attributes returned." + ); } public function testGetNestedOptionsCustomerAttributesMetadata() From 748a9dc9f6dcfbe0ef3df62cb5ebc192a7afee8e Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Fri, 23 Nov 2018 08:58:25 +0200 Subject: [PATCH 12/88] MAGETWO-89438: Advanced pricing the bulk discounts by percentage returns error when set --- ...nValidateApplyingTierPriceWithEmptyDiscountValueTest.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml index bf94971ee9e87..4f060bf40b4e3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml @@ -12,6 +12,7 @@ <features value="Apply tier price"/> <title value="Apply Tier Price with empty discount value"/> <description value="Validate applying tier price to product"/> + <stories value="Apply Tier Price with empty discount value" /> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-96484"/> <group value="product"/> @@ -20,14 +21,12 @@ <createData entity="_defaultCategory" stepKey="createCategory"/> <createData entity="SimpleProduct" stepKey="createSimpleProduct"> <requiredEntity createDataKey="createCategory"/> - <field key="price">100</field> </createData> </before> <after> <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> - <waitForPageLoad time="30" stepKey="waitForProductIndexPageLoad"/> <actionGroup ref="AdminResetProductGridToDefaultViewActionGroup" stepKey="resetGridToDefaultKeywordSearch"/> <actionGroup ref="logout" stepKey="logoutFromAdmin"/> </after> @@ -39,7 +38,6 @@ <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProductPage"> <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> - <waitForPageLoad stepKey="waitForProductPage"/> <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton"/> <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForCustomerGroupPriceAddButton"/> <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="addCustomerGroupPrice"/> @@ -49,7 +47,7 @@ <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton"/> <see selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageError}}" userInput="This is a required field." stepKey="assertPercentageError"/> <fillField selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageValuePriceInput('0')}}" userInput="10" stepKey="setPercentageValue"/> - <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton2"/> + <click selector="{{AdminProductFormAdvancedPricingSection.doneButton}}" stepKey="clickDoneButton1"/> <dontSee selector="{{AdminProductFormAdvancedPricingSection.productTierPricePercentageError}}" userInput="This is a required field." stepKey="assertNoPercentageError"/> <actionGroup ref="SaveProductOnProductPageOnAdmin" stepKey="saveProduct"/> </test> From 8c0a88907dfd3e31cd565d4b618fb0e427777742 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Fri, 23 Nov 2018 09:11:25 +0200 Subject: [PATCH 13/88] MAGETWO-86983: Reward Points Balance Update Emails are not being sent when balance change initiated by store front - Fixed an issue with incorrect work of 'Subscribe for Balance Updates' functionality - Fixed integration test - Fixed API test --- .../testsuite/Magento/Customer/Api/CustomerMetadataTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php index 61121de9cb336..6a68925f76cbc 100644 --- a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerMetadataTest.php @@ -214,8 +214,7 @@ public function testGetCustomAttributesMetadata() $attributeMetadata = $this->_webApiCall($serviceInfo); - // There are no default custom attributes. - $this->assertCount(0, $attributeMetadata); + $this->assertCount(count($this->customerMetadata->getCustomAttributesMetadata()), $attributeMetadata); } /** From 94c9569c6823995500a95d77446ea77ff7ac3ad9 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Fri, 23 Nov 2018 12:12:12 +0200 Subject: [PATCH 14/88] MAGETWO-91138: Making order in admin with grouped product by adding it by sku with empty qty field leads to unability to order --- .../AdminGroupedProductActionGroup.xml | 26 +++++++++++++++++++ .../Test/Mftf/Data/GroupedProductData.xml | 9 +++++++ .../AdminAddProductsToGroupPanelSection.xml | 19 ++++++++++++++ ...AdminProductFormGroupedProductsSection.xml | 15 +++++++++++ .../Test/Mftf/Page/AdminOrderCreatePage.xml | 2 ++ ...minOrderConfigureGroupedProductSection.xml | 15 +++++++++++ .../Section/AdminOrderFormItemsSection.xml | 1 + .../AdminOrderStoreScopeTreeSection.xml | 16 ++++++++++++ 8 files changed, 103 insertions(+) create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminAddProductsToGroupPanelSection.xml create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml new file mode 100644 index 0000000000000..38ee19697bd3e --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAssignProductToGroup"> + <arguments> + <argument name="product"/> + </arguments> + + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection"/> + <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection"/> + <click selector="body" stepKey="clickBodyToCorrectFocusGrouped"/> + <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroup"/> + <conditionalClick selector="{{AdminAddProductsToGroupPanelSection.clearFilters}}" dependentSelector="{{AdminAddProductsToGroupPanelSection.clearFilters}}" visible="true" stepKey="clearExistingFilters"/> + <click selector="{{AdminAddProductsToGroupPanelSection.filters}}" stepKey="showFiltersPanel"/> + <fillField userInput="{{product.name}}" selector="{{AdminAddProductsToGroupPanelSection.nameFilter}}" stepKey="fillNameFilter"/> + <click selector="{{AdminAddProductsToGroupPanelSection.applyFilters}}" stepKey="clickApplyFilters"/> + <click selector="{{AdminAddProductsToGroupPanelSection.firstCheckbox}}" stepKey="selectProduct"/> + <click selector="{{AdminAddProductsToGroupPanelSection.addSelectedProducts}}" stepKey="clickAddSelectedGroupProducts"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml index e760b877fa33d..4d979953a934e 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Data/GroupedProductData.xml @@ -8,6 +8,15 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="GroupedProduct" type="product"> + <data key="sku" unique="suffix">groupedproduct</data> + <data key="type_id">grouped</data> + <data key="attribute_set_id">4</data> + <data key="name" unique="suffix">GroupedProduct</data> + <data key="status">1</data> + <data key="urlKey" unique="suffix">groupedproduct</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + </entity> <entity name="ApiGroupedProduct" type="product3"> <data key="sku" unique="suffix">api-grouped-product</data> <data key="type_id">grouped</data> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminAddProductsToGroupPanelSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminAddProductsToGroupPanelSection.xml new file mode 100644 index 0000000000000..a0de10e580dea --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminAddProductsToGroupPanelSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminAddProductsToGroupPanelSection"> + <element name="addSelectedProducts" type="button" selector=".product_form_product_form_grouped_grouped_products_modal button.action-primary" timeout="30"/> + <element name="clearFilters" type="button" selector=".product_form_product_form_grouped_grouped_products_modal [data-action='grid-filter-reset']" timeout="30"/> + <element name="filters" type="button" selector=".product_form_product_form_grouped_grouped_products_modal [data-action='grid-filter-expand']" timeout="30"/> + <element name="applyFilters" type="button" selector=".product_form_product_form_grouped_grouped_products_modal [data-action='grid-filter-apply']" timeout="30"/> + <element name="nameFilter" type="input" selector=".product_form_product_form_grouped_grouped_products_modal [name='name']"/> + <element name="firstCheckbox" type="input" selector=".product_form_product_form_grouped_grouped_products_modal tr[data-repeat-index='0'] .admin__control-checkbox"/> + </section> +</sections> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml new file mode 100644 index 0000000000000..c653219d73d39 --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminProductFormGroupedProductsSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminProductFormGroupedProductsSection"> + <element name="toggleGroupedProduct" type="button" selector="div[data-index=grouped] .admin__collapsible-title"/> + <element name="addProductsToGroup" type="button" selector="button[data-index='grouped_products_button']" timeout="30"/> + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml index 6522dbf3d25ce..6e6f3bdad8457 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml @@ -18,5 +18,7 @@ <section name="AdminOrderFormTotalSection"/> <section name="AdminOrderCustomersGridSection"/> <section name="AdminOrderFormConfigureProductSection"/> + <section name="AdminOrderConfigureGroupedProductSection"/> + <section name="AdminOrderStoreScopeTreeSection"/> </page> </pages> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml new file mode 100644 index 0000000000000..04f9f68a27589 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminOrderConfigureGroupedProductSection"> + <element name="configureProductOk" type="button" selector="[data-role='modal']._show [data-role='action']" timeout="30"/> + <element name="configureProductQtyField" type="input" selector="#super-product-table tr:nth-of-type({{index}}) td.col-qty input.qty" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml index c4cf5bd05bb6f..291103bd7a2da 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml @@ -26,5 +26,6 @@ <element name="removeItems" type="select" selector="//span[text()='{{arg}}']/parent::td/following-sibling::td/select[@class='admin__control-select']" parameterized="true"/> <element name="applyCoupon" type="input" selector="#coupons:code"/> <element name="customPriceField" type="input" selector="//*[@class='custom-price-block']/following-sibling::input"/> + <element name="productRowBySku" type="block" selector="//*[@id='order-items_grid']//tbody//td[contains(@class,'col-product')]/span[starts-with(@id,'order_item_') and text()='{{productName}}']/ancestor::tr" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml new file mode 100644 index 0000000000000..cbe17499319f9 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderStoreScopeTreeSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminOrderStoreScopeTreeSection"> + <element name="storeTree" type="text" selector="div.tree-store-scope"/> + <element name="storeOption" type="radio" selector="//div[contains(@class, 'tree-store-scope')]//label[contains(text(), '{{name}}')]/preceding-sibling::input" parameterized="true" timeout="30"/> + <element name="storeForOrder" type="radio" selector="//div[contains(@class, 'tree-store-scope')]//label[contains(text(), '{{arg}}')]" parameterized="true" timeout="30"/> + </section> +</sections> From 2347a52deea888e045f76a1607397b106f44d9fa Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Mon, 26 Nov 2018 10:26:54 +0200 Subject: [PATCH 15/88] MAGETWO-86396: Search synonyms results missing for words including hyphen and numbers --- .../Catalog/Test/Repository/CatalogProductSimple.xml | 2 +- .../Search/Adapter/Mysql/Query/Builder/Match.php | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml index 721b0ff570079..e90ca6bf7868a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml @@ -41,7 +41,7 @@ <field name="attribute_set_id" xsi:type="array"> <item name="dataset" xsi:type="string">default</item> </field> - <field name="name" xsi:type="string">Product \'!@#$%^&*()+:;\\|}{][?=-~` %isolation%</field> + <field name="name" xsi:type="string">Product \'!@#$%^&*()+:;\\|}{][?=~` %isolation%</field> <field name="sku" xsi:type="string">sku_simple_product_%isolation%</field> <field name="is_virtual" xsi:type="string">No</field> <field name="product_has_weight" xsi:type="string">This item has weight</field> diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php index 8e3758817adf0..28e321d4c5d47 100644 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php +++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/Query/Builder/Match.php @@ -15,11 +15,16 @@ use Magento\Framework\Search\Adapter\Preprocessor\PreprocessorInterface; /** + * Class for building select where condition. + * * @api */ class Match implements QueryInterface { - const SPECIAL_CHARACTERS = '-+~/\\<>\'":*$#@()!,.?`=%&^'; + /** + * @var string + */ + const SPECIAL_CHARACTERS = '+~/\\<>\'":*$#@()!,.?`=%&^'; const MINIMAL_CHARACTER_LENGTH = 3; @@ -69,7 +74,7 @@ public function __construct( } /** - * {@inheritdoc} + * @inheritdoc */ public function build( ScoreBuilder $scoreBuilder, @@ -113,6 +118,8 @@ public function build( } /** + * Prepare query value for build function. + * * @param string $queryValue * @param string $conditionType * @return string From 083c208d143b026a9c66d047e8bb85f71d72b5ba Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 26 Nov 2018 11:17:38 +0200 Subject: [PATCH 16/88] MAGETWO-89546: Navigation Menu problem on Mobile theme --- lib/web/mage/menu.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index e4ccbdf325ecc..5e14e20ef5d8e 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -438,6 +438,9 @@ define([ event.preventDefault(); target = $(event.target).closest('.ui-menu-item'); + if (target.length) { + target.get(0).scrollIntoView(); + } if (!target.hasClass('level-top') || !target.has('.ui-menu').length) { window.location.href = target.find('> a').attr('href'); From 9787b947187664de3c40e52ae24ca7168c98975a Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Mon, 26 Nov 2018 12:12:37 +0200 Subject: [PATCH 17/88] MAGETWO-85699: Multiselect attribute values is not searchable under Quick Search when more than one value is selected --- .../Indexer/Fulltext/Action/DataProvider.php | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php index 286b6427c8132..7a94dcb78cfd5 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php @@ -12,6 +12,8 @@ use Magento\Store\Model\Store; /** + * Catalog search full text search data provider. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.TooManyFields) * @api @@ -571,8 +573,8 @@ public function prepareProductIndex($indexData, $productData, $storeId) } } foreach ($indexData as $entityId => $attributeData) { - foreach ($attributeData as $attributeId => $attributeValue) { - $value = $this->getAttributeValue($attributeId, $attributeValue, $storeId); + foreach ($attributeData as $attributeId => $attributeValues) { + $value = $this->getAttributeValue($attributeId, $attributeValues, $storeId); if (!empty($value)) { if (isset($index[$attributeId])) { $index[$attributeId][$entityId] = $value; @@ -603,16 +605,16 @@ public function prepareProductIndex($indexData, $productData, $storeId) * Retrieve attribute source value for search * * @param int $attributeId - * @param mixed $valueId + * @param mixed $valueIds * @param int $storeId * @return string */ - private function getAttributeValue($attributeId, $valueId, $storeId) + private function getAttributeValue($attributeId, $valueIds, $storeId) { $attribute = $this->getSearchableAttribute($attributeId); - $value = $this->engine->processAttributeValue($attribute, $valueId); + $value = $this->engine->processAttributeValue($attribute, $valueIds); if (false !== $value) { - $optionValue = $this->getAttributeOptionValue($attributeId, $valueId, $storeId); + $optionValue = $this->getAttributeOptionValue($attributeId, $valueIds, $storeId); if (null === $optionValue) { $value = preg_replace('/\s+/iu', ' ', trim(strip_tags($value))); } else { @@ -627,13 +629,15 @@ private function getAttributeValue($attributeId, $valueId, $storeId) * Get attribute option value * * @param int $attributeId - * @param int $valueId + * @param int|string $valueIds * @param int $storeId * @return null|string */ - private function getAttributeOptionValue($attributeId, $valueId, $storeId) + private function getAttributeOptionValue($attributeId, $valueIds, $storeId) { $optionKey = $attributeId . '-' . $storeId; + $attributeValueIds = explode(',', $valueIds); + $attributeOptionValue = ''; if (!array_key_exists($optionKey, $this->attributeOptions) ) { $attribute = $this->getSearchableAttribute($attributeId); @@ -649,6 +653,12 @@ private function getAttributeOptionValue($attributeId, $valueId, $storeId) } } - return $this->attributeOptions[$optionKey][$valueId] ?? null; + foreach ($attributeValueIds as $attributeValueId) { + if (isset($this->attributeOptions[$optionKey][$attributeValueId])) { + $attributeOptionValue .= $this->attributeOptions[$optionKey][$attributeValueId] . ' '; + } + } + + return empty($attributeOptionValue) ? null : trim($attributeOptionValue); } } From b13aa2b770671d77873b920e4d036a4cf94cf131 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 26 Nov 2018 14:06:43 +0200 Subject: [PATCH 18/88] MAGETWO-89546: Navigation Menu problem on Mobile theme --- lib/web/mage/menu.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index 5e14e20ef5d8e..0274954de9ae4 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -438,6 +438,7 @@ define([ event.preventDefault(); target = $(event.target).closest('.ui-menu-item'); + if (target.length) { target.get(0).scrollIntoView(); } From bf08f7a81d9581d64b32ee4a26bc7cedd651ece5 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 26 Nov 2018 14:52:29 +0200 Subject: [PATCH 19/88] MAGETWO-91138: Making order in admin with grouped product by adding it by sku with empty qty field leads to unability to order --- .../Test/Mftf/Page/AdminOrderCreatePage.xml | 14 ++++++++++++++ .../Test/Mftf/Page/AdminProductCreatePage.xml | 15 +++++++++++++++ .../AdminOrderConfigureGroupedProductSection.xml | 0 .../Sales/Test/Mftf/Page/AdminOrderCreatePage.xml | 1 - .../Mftf/Section/AdminOrderFormItemsSection.xml | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminOrderCreatePage.xml create mode 100644 app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminProductCreatePage.xml rename app/code/Magento/{Sales => GroupedProduct}/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml (100%) diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminOrderCreatePage.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminOrderCreatePage.xml new file mode 100644 index 0000000000000..d9c6c4023c07d --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminOrderCreatePage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminOrderCreatePage" url="sales/order_create/index" area="admin" module="Magento_Sales"> + <section name="AdminOrderConfigureGroupedProductSection"/> + </page> +</pages> diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminProductCreatePage.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminProductCreatePage.xml new file mode 100644 index 0000000000000..4fd214111de93 --- /dev/null +++ b/app/code/Magento/GroupedProduct/Test/Mftf/Page/AdminProductCreatePage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminProductCreatePage" url="catalog/product/new/set/{{set}}/type/{{type}}/" area="admin" module="Magento_Catalog" parameterized="true"> + <section name="AdminAddProductsToGroupPanelSection"/> + <section name="AdminProductFormGroupedProductsSection"/> + </page> +</pages> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml b/app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml similarity index 100% rename from app/code/Magento/Sales/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml rename to app/code/Magento/GroupedProduct/Test/Mftf/Section/AdminOrderConfigureGroupedProductSection.xml diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml index 6e6f3bdad8457..e67a2c3b961d9 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminOrderCreatePage.xml @@ -18,7 +18,6 @@ <section name="AdminOrderFormTotalSection"/> <section name="AdminOrderCustomersGridSection"/> <section name="AdminOrderFormConfigureProductSection"/> - <section name="AdminOrderConfigureGroupedProductSection"/> <section name="AdminOrderStoreScopeTreeSection"/> </page> </pages> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml index 291103bd7a2da..00a7688a3f74e 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml @@ -27,5 +27,6 @@ <element name="applyCoupon" type="input" selector="#coupons:code"/> <element name="customPriceField" type="input" selector="//*[@class='custom-price-block']/following-sibling::input"/> <element name="productRowBySku" type="block" selector="//*[@id='order-items_grid']//tbody//td[contains(@class,'col-product')]/span[starts-with(@id,'order_item_') and text()='{{productName}}']/ancestor::tr" parameterized="true"/> + <element name="itemsOrderedSummaryText" type="text" selector="#order-items_grid tfoot tr"/> </section> </sections> From a751da1ced71e583dfe9942a7973b78fa22f6ce9 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 26 Nov 2018 16:27:26 +0200 Subject: [PATCH 20/88] MAGETWO-89546: Navigation Menu problem on Mobile theme - Fix unstable integration tests --- .../testsuite/Magento/Cms/Model/BlockTest.php | 23 ++++++--- .../testsuite/Magento/Cms/Model/PageTest.php | 47 +++++++++++++------ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php index 9b2bb67c55da1..a4ffa43153492 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php @@ -6,10 +6,9 @@ namespace Magento\Cms\Model; use Magento\Cms\Api\BlockRepositoryInterface; -use Magento\Cms\Model\BlockFactory; use Magento\Cms\Model\ResourceModel\Block; +use Magento\Framework\App\ResourceConnection; use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\Stdlib\DateTime\DateTime; use Magento\TestFramework\Helper\Bootstrap; use PHPUnit\Framework\TestCase; @@ -58,22 +57,32 @@ protected function setUp() */ public function testUpdateTime(array $blockData) { + /** @var \Magento\Framework\DB\Adapter\AdapterInterface $db */ + $db = $this->objectManager->get(\Magento\Framework\App\ResourceConnection::class) + ->getConnection(ResourceConnection::DEFAULT_CONNECTION); + # Prepare and save the temporary block $tempBlock = $this->blockFactory->create(); $tempBlock->setData($blockData); + $beforeTimestamp = $db->fetchOne('SELECT UNIX_TIMESTAMP()'); $this->blockResource->save($tempBlock); + $afterTimestamp = $db->fetchOne('SELECT UNIX_TIMESTAMP()'); # Load previously created block and compare update_time field $block = $this->blockRepository->getById($tempBlock->getId()); - $date = $this->objectManager->get(DateTime::class)->date(); - $this->assertEquals($date, $block->getUpdateTime()); + $blockTimestamp = strtotime($block->getUpdateTime()); + + /** These checks prevent a race condition */ + $this->assertGreaterThanOrEqual($beforeTimestamp, $blockTimestamp); + $this->assertLessThanOrEqual($afterTimestamp, $blockTimestamp); } /** * Data provider "testUpdateTime" method + * * @return array */ - public function testUpdateTimeDataProvider() + public function testUpdateTimeDataProvider(): array { return [ [ @@ -82,8 +91,8 @@ public function testUpdateTimeDataProvider() 'stores' => [0], 'identifier' => 'test-identifier', 'content' => 'Test content', - 'is_active' => 1 - ] + 'is_active' => 1, + ], ] ]; } diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php index c8040861b08eb..475b31b2cf03b 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php @@ -6,23 +6,32 @@ namespace Magento\Cms\Model; use Magento\Cms\Api\PageRepositoryInterface; -use Magento\Framework\Stdlib\DateTime\DateTime; +use Magento\Framework\App\ResourceConnection; /** * @magentoAppArea adminhtml */ class PageTest extends \PHPUnit\Framework\TestCase { + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @inheritdoc + */ protected function setUp() { - $user = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $user = $this->objectManager->create( \Magento\User\Model\User::class )->loadByUsername( \Magento\TestFramework\Bootstrap::ADMIN_NAME ); /** @var $session \Magento\Backend\Model\Auth\Session */ - $session = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + $session = $this->objectManager->get( \Magento\Backend\Model\Auth\Session::class ); $session->setUser($user); @@ -34,9 +43,8 @@ protected function setUp() */ public function testGenerateIdentifierFromTitle($data, $expectedIdentifier) { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); /** @var \Magento\Cms\Model\Page $page */ - $page = $objectManager->create(\Magento\Cms\Model\Page::class); + $page = $this->objectManager->create(\Magento\Cms\Model\Page::class); $page->setData($data); $page->save(); $this->assertEquals($expectedIdentifier, $page->getIdentifier()); @@ -47,28 +55,39 @@ public function testGenerateIdentifierFromTitle($data, $expectedIdentifier) */ public function testUpdateTime() { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + /** @var \Magento\Framework\DB\Adapter\AdapterInterface $db */ + $db = $this->objectManager->get(\Magento\Framework\App\ResourceConnection::class) + ->getConnection(ResourceConnection::DEFAULT_CONNECTION); + /** @var \Magento\Cms\Model\Page $page */ - $page = $objectManager->create(\Magento\Cms\Model\Page::class); + $page = $this->objectManager->create(\Magento\Cms\Model\Page::class); $page->setData(['title' => 'Test', 'stores' => [1]]); + $beforeTimestamp = $db->fetchOne('SELECT UNIX_TIMESTAMP()'); $page->save(); - $page = $objectManager->get(PageRepositoryInterface::class)->getById($page->getId()); - $date = $objectManager->get(DateTime::class)->date(); - $this->assertEquals($date, $page->getUpdateTime()); + $afterTimestamp = $db->fetchOne('SELECT UNIX_TIMESTAMP()'); + $page = $this->objectManager->get(PageRepositoryInterface::class)->getById($page->getId()); + $pageTimestamp = strtotime($page->getUpdateTime()); + + /** These checks prevent a race condition */ + $this->assertGreaterThanOrEqual($beforeTimestamp, $pageTimestamp); + $this->assertLessThanOrEqual($afterTimestamp, $pageTimestamp); } - public function generateIdentifierFromTitleDataProvider() + /** + * @return array + */ + public function generateIdentifierFromTitleDataProvider(): array { return [ ['data' => ['title' => 'Test title', 'stores' => [1]], 'expectedIdentifier' => 'test-title'], [ 'data' => ['title' => 'Кирилический заголовок', 'stores' => [1]], - 'expectedIdentifier' => 'kirilicheskij-zagolovok' + 'expectedIdentifier' => 'kirilicheskij-zagolovok', ], [ 'data' => ['title' => 'Test title', 'identifier' => 'custom-identifier', 'stores' => [1]], - 'expectedIdentifier' => 'custom-identifier' - ] + 'expectedIdentifier' => 'custom-identifier', + ], ]; } } From 4cea33880339019840237f6ba4d6a10233328f8a Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 26 Nov 2018 20:38:47 +0200 Subject: [PATCH 21/88] MAGETWO-91138: Making order in admin with grouped product by adding it by sku with empty qty field leads to unability to order --- .../Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml index 38ee19697bd3e..b827115f6e066 100644 --- a/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml +++ b/app/code/Magento/GroupedProduct/Test/Mftf/ActionGroup/AdminGroupedProductActionGroup.xml @@ -14,7 +14,6 @@ <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection"/> <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection"/> - <click selector="body" stepKey="clickBodyToCorrectFocusGrouped"/> <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroup"/> <conditionalClick selector="{{AdminAddProductsToGroupPanelSection.clearFilters}}" dependentSelector="{{AdminAddProductsToGroupPanelSection.clearFilters}}" visible="true" stepKey="clearExistingFilters"/> <click selector="{{AdminAddProductsToGroupPanelSection.filters}}" stepKey="showFiltersPanel"/> From 1ae7fbe8d6039a297a6aa642e9303d4eab362d06 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Tue, 27 Nov 2018 08:11:28 +0200 Subject: [PATCH 22/88] MAGETWO-91403: Instantiating WYSIWYG in DynamicRows --- .../view/base/web/js/form/element/wysiwyg.js | 21 ++++++++++++++++++- .../Framework/Data/Form/Element/Editor.php | 9 ++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js index b8cd4a0f2c892..547e6cde59839 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js @@ -18,7 +18,7 @@ define([ return Abstract.extend({ defaults: { elementSelector: 'textarea', - value: '', + suffixRegExpPattern: '\\${ \\$.wysiwygUniqueSuffix }', $wysiwygEditorButton: '', links: { value: '${ $.provider }:${ $.dataScope }' @@ -52,6 +52,25 @@ define([ return this; }, + /** @inheritdoc */ + initConfig: function (config) { + var pattern = config.suffixRegExpPattern || this.constructor.defaults.suffixRegExpPattern; + + config.content = config.content.replace(new RegExp(pattern, 'g'), this.getUniqueSuffix(config)); + this._super(); + + return this; + }, + + /** + * Build unique id based on name, underscore separated. + * + * @param {Object} config + */ + getUniqueSuffix: function (config) { + return config.name.replace(/(\.|-)/g, '_'); + }, + /** * * @returns {exports} diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php index 6ed2d8293e61d..412fedaec3831 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php @@ -487,4 +487,13 @@ protected function isToggleButtonVisible() { return !$this->getConfig()->hasData('toggle_button') || $this->getConfig('toggle_button'); } + + /** + * @inheritdoc + */ + public function getHtmlId() + { + $suffix = $this->getConfig('dynamic_id') ? '${ $.wysiwygUniqueSuffix }' : ''; + return parent::getHtmlId() . $suffix; + } } From fbc3b000e001006d71edff6b22a40d7357e190c5 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Tue, 27 Nov 2018 10:37:14 +0200 Subject: [PATCH 23/88] MAGETWO-89546: Navigation Menu problem on Mobile theme - Fix unstable integration tests --- .../testsuite/Magento/Cms/Model/BlockTest.php | 17 +++++++++-------- .../testsuite/Magento/Cms/Model/PageTest.php | 18 +++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php index a4ffa43153492..bc419f527830d 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/BlockTest.php @@ -37,28 +37,29 @@ class BlockTest extends TestCase */ private $blockRepository; + /** + * @inheritdoc + */ protected function setUp() { $this->objectManager = Bootstrap::getObjectManager(); - - /** @var BlockFactory $blockFactory */ - /** @var Block $blockResource */ $this->blockResource = $this->objectManager->create(Block::class); $this->blockFactory = $this->objectManager->create(BlockFactory::class); $this->blockRepository = $this->objectManager->create(BlockRepositoryInterface::class); } /** - * Test UpdateTime + * Tests update time. + * * @param array $blockData - * @throws \Exception + * @return void * @magentoDbIsolation enabled * @dataProvider testUpdateTimeDataProvider */ public function testUpdateTime(array $blockData) { /** @var \Magento\Framework\DB\Adapter\AdapterInterface $db */ - $db = $this->objectManager->get(\Magento\Framework\App\ResourceConnection::class) + $db = $this->objectManager->get(ResourceConnection::class) ->getConnection(ResourceConnection::DEFAULT_CONNECTION); # Prepare and save the temporary block @@ -78,7 +79,7 @@ public function testUpdateTime(array $blockData) } /** - * Data provider "testUpdateTime" method + * Data provider "testUpdateTime" method. * * @return array */ @@ -93,7 +94,7 @@ public function testUpdateTimeDataProvider(): array 'content' => 'Test content', 'is_active' => 1, ], - ] + ], ]; } } diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php index 475b31b2cf03b..c3553717d0224 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/PageTest.php @@ -39,12 +39,15 @@ protected function setUp() /** * @magentoDbIsolation enabled - * @dataProvider generateIdentifierFromTitleDataProvider + * @dataProvider generateIdentifierFromTitleDataProvider + * @param array $data + * @param string $expectedIdentifier + * @return void */ - public function testGenerateIdentifierFromTitle($data, $expectedIdentifier) + public function testGenerateIdentifierFromTitle(array $data, string $expectedIdentifier) { - /** @var \Magento\Cms\Model\Page $page */ - $page = $this->objectManager->create(\Magento\Cms\Model\Page::class); + /** @var Page $page */ + $page = $this->objectManager->create(Page::class); $page->setData($data); $page->save(); $this->assertEquals($expectedIdentifier, $page->getIdentifier()); @@ -52,15 +55,16 @@ public function testGenerateIdentifierFromTitle($data, $expectedIdentifier) /** * @magentoDbIsolation enabled + * @return void */ public function testUpdateTime() { /** @var \Magento\Framework\DB\Adapter\AdapterInterface $db */ - $db = $this->objectManager->get(\Magento\Framework\App\ResourceConnection::class) + $db = $this->objectManager->get(ResourceConnection::class) ->getConnection(ResourceConnection::DEFAULT_CONNECTION); - /** @var \Magento\Cms\Model\Page $page */ - $page = $this->objectManager->create(\Magento\Cms\Model\Page::class); + /** @var Page $page */ + $page = $this->objectManager->create(Page::class); $page->setData(['title' => 'Test', 'stores' => [1]]); $beforeTimestamp = $db->fetchOne('SELECT UNIX_TIMESTAMP()'); $page->save(); From cd1128ba5fbe51710fda69e01112acbc658c5320 Mon Sep 17 00:00:00 2001 From: Stas Kozar <stas.kozar@transoftgroup.com> Date: Tue, 27 Nov 2018 12:20:31 +0200 Subject: [PATCH 24/88] MAGETWO-95067: Checkout data (shipping address etc) not persistant after cart update --- .../Magento/Customer/view/frontend/web/js/customer-data.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js index 39e3f8d95ee3b..66d37cb84e9cb 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/customer-data.js +++ b/app/code/Magento/Customer/view/frontend/web/js/customer-data.js @@ -216,6 +216,9 @@ define([ $.cookieStorage.set(privateContentVersion, privateContent); } $.localStorage.set(privateContentVersion, privateContent); + _.each(dataProvider.getFromStorage(storage.keys()), function (sectionData, sectionName) { + buffer.notify(sectionName, sectionData); + }); this.reload([], false); isLoading = true; } else if (expiredSectionNames.length > 0) { From 0a9e27f8f648443515774c7f54ec25a61773fe1d Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Tue, 27 Nov 2018 12:23:26 +0200 Subject: [PATCH 25/88] MAGETWO-88736: Issue with Newsletter subscriptions --- .../Model/ResourceModel/Subscriber.php | 57 ++++++++----------- .../Magento/Newsletter/Model/Subscriber.php | 3 + 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php index 131eca5f33487..33e3826e9180b 100644 --- a/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/ResourceModel/Subscriber.php @@ -132,43 +132,34 @@ public function loadByEmail($subscriberEmail) */ public function loadByCustomerData(\Magento\Customer\Api\Data\CustomerInterface $customer) { - $storeId = (int)$customer->getStoreId() ?: $this->storeManager - ->getWebsite($customer->getWebsiteId())->getDefaultStore()->getId(); - - $select = $this->connection - ->select() - ->from($this->getMainTable()) - ->where('customer_id=:customer_id and store_id=:store_id'); - - $result = $this->connection - ->fetchRow( - $select, - [ - 'customer_id' => $customer->getId(), - 'store_id' => $storeId - ] - ); + $storeIds = $this->storeManager->getWebsite($customer->getWebsiteId())->getStoreIds(); + + if ($customer->getId()) { + $select = $this->connection + ->select() + ->from($this->getMainTable()) + ->where('customer_id = ?', $customer->getId()) + ->where('store_id IN (?)', $storeIds); + + $result = $this->connection->fetchRow($select); - if ($result) { - return $result; + if ($result) { + return $result; + } } - $select = $this->connection - ->select() - ->from($this->getMainTable()) - ->where('subscriber_email=:subscriber_email and store_id=:store_id'); - - $result = $this->connection - ->fetchRow( - $select, - [ - 'subscriber_email' => $customer->getEmail(), - 'store_id' => $storeId - ] - ); + if ($customer->getEmail()) { + $select = $this->connection + ->select() + ->from($this->getMainTable()) + ->where('subscriber_email = ?', $customer->getEmail()) + ->where('store_id IN (?)', $storeIds); + + $result = $this->connection->fetchRow($select); - if ($result) { - return $result; + if ($result) { + return $result; + } } return []; diff --git a/app/code/Magento/Newsletter/Model/Subscriber.php b/app/code/Magento/Newsletter/Model/Subscriber.php index a1d929d8db7bf..48a89129f3098 100644 --- a/app/code/Magento/Newsletter/Model/Subscriber.php +++ b/app/code/Magento/Newsletter/Model/Subscriber.php @@ -389,6 +389,9 @@ public function loadByCustomerId($customerId) try { $customerData = $this->customerRepository->getById($customerId); $customerData->setStoreId($this->_storeManager->getStore()->getId()); + if ($customerData->getWebsiteId() === null) { + $customerData->setWebsiteId($this->_storeManager->getStore()->getWebsiteId()); + } $data = $this->getResource()->loadByCustomerData($customerData); $this->addData($data); if (!empty($data) && $customerData->getId() && !$this->getCustomerId()) { From aa84daa1e5d3fb8ec9dd6e3b27d58677049c4c6e Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Tue, 27 Nov 2018 14:13:32 +0200 Subject: [PATCH 26/88] MAGETWO-89397: Wrong Checkout Totals Sort Order in cart --- .../Mftf/ActionGroup/CheckoutActionGroup.xml | 8 ++ .../StorefrontCheckoutCartSummarySection.xml | 1 + .../CheckoutTotalsSortOrderInCartTest.xml | 47 ++++++++++++ .../Sales/Test/Mftf/Data/SalesConfigData.xml | 17 ++++- .../Test/Mftf/Metadata/sales_config-meta.xml | 76 +++++++++++++++++++ .../StorefrontSalesRuleActionGroup.xml | 24 ++++++ .../Test/Mftf/Data/SalesRuleData.xml | 28 +++++++ .../frontend/layout/checkout_cart_index.xml | 12 +-- 8 files changed, 203 insertions(+), 10 deletions(-) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml create mode 100644 app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index aa168899ddb02..08679765f5eb2 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -73,4 +73,12 @@ <conditionalClick selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" dependentSelector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" visible="true" stepKey="selectFlatRateShippingMethod"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskForNextButton"/> </actionGroup> + + <actionGroup name="CheckTotalsSortOrderInSummarySection"> + <arguments> + <argument name="elementName" type="string"/> + <argument name="positionNumber" type="integer"/> + </arguments> + <see userInput="{{elementName}}" selector="{{StorefrontCheckoutCartSummarySection.totalsElementByPosition(positionNumber)}}" stepKey="assertElementPosition"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutCartSummarySection.xml b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutCartSummarySection.xml index a7c5fb484b2bf..a58fa77bca18b 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutCartSummarySection.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Section/StorefrontCheckoutCartSummarySection.xml @@ -21,5 +21,6 @@ <element name="shippingHeading" type="button" selector="#block-shipping-heading"/> <element name="blockSummary" type="button" selector="#block-summary"/> <element name="discountAmount" type="text" selector="td[data-th='Discount']"/> + <element name="totalsElementByPosition" type="text" selector=".data.table.totals > tbody tr:nth-of-type({{value}}) > th" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml new file mode 100644 index 0000000000000..1368062bddd2c --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml @@ -0,0 +1,47 @@ +<?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="CheckoutTotalsSortOrderInCartTest"> + <annotations> + <title value="Checkout Totals Sort Order configuration and displaying in cart"/> + <stories value="MAGETWO-89397: Wrong Checkout Totals Sort Order in cart"/> + <description value="Checkout Totals Sort Order configuration and displaying in cart"/> + <features value="Checkout"/> + <severity value="AVERAGE"/> + <testCaseId value="MAGETWO-96635"/> + <group value="checkout"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="defaultCategory"/> + <createData entity="SimpleProduct" stepKey="simpleProduct"> + <requiredEntity createDataKey="defaultCategory"/> + </createData> + <createData entity="ApiCartRule1" stepKey="cartRule"/> + <createData entity="CheckoutShippingTotalsSortOrder" stepKey="setConfigShippingTotalsSortOrder"/> + </before> + + <after> + <createData entity="DefaultCheckoutTotalsSortOrder" stepKey="setDefaultTotalsSortOrder"/> + <deleteData createDataKey="cartRule" stepKey="deleteCartRule"/> + <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="defaultCategory" stepKey="deleteCategory"/> + </after> + + <actionGroup ref="VerifyDiscountAmount" stepKey="verifyStorefront"> + <argument name="productUrl" value="$$simpleProduct.sku$$.html"/> + <argument name="quantity" value="1"/> + <argument name="expectedDiscount" value="-$100"/> + </actionGroup> + + <actionGroup ref="CheckTotalsSortOrderInSummarySection" stepKey="checkTotalsSortOrderInSummarySection"> + <argument name="elementName" value="Shipping (Flat Rate - Fixed)"/> + <argument name="positionNumber" value="3"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml b/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml index 035c3949820f6..3a8449caae643 100644 --- a/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml +++ b/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="EnabledMinimumOrderAmount500" type="sales_minimum_order"> + <entity name="EnabledMinimumOrderAmount500" type="sales_groups"> <requiredEntity type="active">EnableMinimumOrderCheck</requiredEntity> <requiredEntity type="amount">MinimumOrderAmount500</requiredEntity> </entity> @@ -18,10 +18,23 @@ <data key="value">500</data> </entity> - <entity name="DisabledMinimumOrderAmount" type="sales_minimum_order"> + <entity name="DisabledMinimumOrderAmount" type="sales_groups"> <requiredEntity type="active">DisableMinimumOrderCheck</requiredEntity> </entity> <entity name="DisableMinimumOrderCheck" type="active"> <data key="value">0</data> </entity> + + <entity name="CheckoutShippingTotalsSortOrder" type="checkout_totals_sort_order"> + <requiredEntity type="shipping">ShippingTotalsSortOrder</requiredEntity> + </entity> + <entity name="ShippingTotalsSortOrder" type="shipping"> + <data key="value">27</data> + </entity> + <entity name="DefaultCheckoutTotalsSortOrder" type="default_checkout_totals_sort_order"> + <requiredEntity type="checkoutTotalFlagZero">DefaultTotalFlagZero</requiredEntity> + </entity> + <entity name="DefaultTotalFlagZero" type="checkoutTotalFlagZero"> + <data key="value">0</data> + </entity> </entities> diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml index 77c8c8fa1c959..e676ca89a422e 100644 --- a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml @@ -20,4 +20,80 @@ </object> </object> </operation> + <operation name="SetCheckoutTotalsSortOrder" dataType="checkout_totals_sort_order" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST" successRegex="/messages-message-success/"> + <object key="groups" dataType="checkout_totals_sort_order"> + <object key="totals_sort" dataType="checkout_totals_sort_order"> + <object key="fields" dataType="checkout_totals_sort_order"> + <object key="subtotal" dataType="subtotal"> + <field key="value">integer</field> + </object> + <object key="discount" dataType="discount"> + <field key="value">integer</field> + </object> + <object key="shipping" dataType="shipping"> + <field key="value">integer</field> + </object> + <object key="tax" dataType="tax"> + <field key="value">integer</field> + </object> + <object key="weee" dataType="weee"> + <field key="value">integer</field> + </object> + <object key="grand_total" dataType="grand_total"> + <field key="value">integer</field> + </object> + <object key="giftcardaccount" dataType="giftcardaccount"> + <field key="value">integer</field> + </object> + <object key="customerbalance" dataType="customerbalance"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </operation> + <operation name="DefaultCheckoutTotalsSortOrder" dataType="default_checkout_totals_sort_order" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST" successRegex="/messages-message-success/"> + <object key="groups" dataType="default_checkout_totals_sort_order"> + <object key="totals_sort" dataType="default_checkout_totals_sort_order"> + <object key="fields" dataType="default_checkout_totals_sort_order"> + <object key="subtotal" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="discount" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="shipping" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="tax" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="weee" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="grand_total" dataType="default_checkout_totals_sort_order"> + <object key="inherit" dataType="checkoutTotalFlagZero"> + <field key="value">integer</field> + </object> + </object> + <object key="giftcardaccount" dataType="giftcardaccount"> + <field key="value">integer</field> + </object> + <object key="customerbalance" dataType="customerbalance"> + <field key="value">integer</field> + </object> + </object> + </object> + </object> + </operation> </operations> diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml new file mode 100644 index 0000000000000..3176721baffda --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="VerifyDiscountAmount"> + <arguments> + <argument name="productUrl" type="string"/> + <argument name="quantity" type="string"/> + <argument name="expectedDiscount" type="string"/> + </arguments> + <amOnPage url="{{productUrl}}" stepKey="goToProductPage"/> + <fillField selector="{{StorefrontProductActionSection.quantity}}" userInput="{{quantity}}" stepKey="fillQuantity"/> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> + <waitForPageLoad stepKey="waitForAddToCart"/> + <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCartPage"/> + <waitForElementVisible selector="{{StorefrontCheckoutCartSummarySection.discountAmount}}" stepKey="waitForDiscountElement"/> + <see selector="{{StorefrontCheckoutCartSummarySection.discountAmount}}" userInput="{{expectedDiscount}}" stepKey="seeDiscountTotal"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml index 28d61e34339ef..764fe16db552a 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml @@ -85,4 +85,32 @@ <entity name="SalesRule100PercentDiscount" extends="TestSalesRule" type="SalesRule"> <data key="discountAmount">100</data> </entity> + <entity name="ApiCartRule1" type="SalesRule"> + <data key="name" unique="suffix">salesRule</data> + <data key="description">Sales Rule Descritpion</data> + <array key="website_ids"> + <item>1</item> + </array> + <array key="customer_group_ids"> + <item>0</item> + <item>1</item> + <item>3</item> + </array> + <data key="uses_per_customer">0</data> + <data key="is_active">true</data> + <data key="stop_rules_processing">true</data> + <data key="is_advanced">true</data> + <data key="sort_order">0</data> + <data key="simple_action">by_percent</data> + <data key="discount_amount">50</data> + <data key="discount_qty">0</data> + <data key="discount_step">0</data> + <data key="apply_to_shipping">false</data> + <data key="times_used">0</data> + <data key="is_rss">true</data> + <data key="coupon_type">NO_COUPON</data> + <data key="use_auto_generation">false</data> + <data key="uses_per_coupon">0</data> + <data key="simple_free_shipping">0</data> + </entity> </entities> diff --git a/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml b/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml index 022403579b237..375324ed4cde6 100644 --- a/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml +++ b/app/code/Magento/SalesRule/view/frontend/layout/checkout_cart_index.xml @@ -13,14 +13,10 @@ <item name="components" xsi:type="array"> <item name="block-totals" xsi:type="array"> <item name="children" xsi:type="array"> - <item name="before_grandtotal" xsi:type="array"> - <item name="children" xsi:type="array"> - <item name="discount" xsi:type="array"> - <item name="component" xsi:type="string">Magento_SalesRule/js/view/cart/totals/discount</item> - <item name="config" xsi:type="array"> - <item name="title" xsi:type="string" translate="true">Discount</item> - </item> - </item> + <item name="discount" xsi:type="array"> + <item name="component" xsi:type="string">Magento_SalesRule/js/view/cart/totals/discount</item> + <item name="config" xsi:type="array"> + <item name="title" xsi:type="string" translate="true">Discount</item> </item> </item> </item> From 4b914865429e1b7f419ce0e744d347391cbb284a Mon Sep 17 00:00:00 2001 From: Stas Kozar <stas.kozar@transoftgroup.com> Date: Tue, 27 Nov 2018 14:57:19 +0200 Subject: [PATCH 27/88] MAGETWO-95067: Checkout data (shipping address etc) not persistant after cart update --- ...StorefrontGuestCheckoutDataPersistTest.xml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml new file mode 100644 index 0000000000000..2185c8de45c73 --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml @@ -0,0 +1,57 @@ +<?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="StorefrontGuestCheckoutDataPersistTest"> + <annotations> + <features value="Checkout"/> + <stories value="MAGETWO-95067: Checkout data (shipping address etc) not persistant after cart update"/> + <title value="Check that checkout data persist after cart update"/> + <description value="Checkout data should be persist after updating cart"/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-96670"/> + <group value="checkout"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + </after> + + <!-- Add simple product to cart --> + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <!-- Navigate to checkout --> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart"/> + <!-- Fill shipping address --> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShipping"> + <argument name="shippingMethod" value="Flat Rate"/> + </actionGroup> + <!-- Add simple product to cart --> + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart2"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <!-- Navigate to checkout --> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart2"/> + <seeInField selector="{{GuestCheckoutShippingSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="assertGuestEmail"/> + <seeInField selector="{{GuestCheckoutShippingSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="assertGuestFirstName"/> + <seeInField selector="{{GuestCheckoutShippingSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="assertGuestLastName"/> + <seeInField selector="{{GuestCheckoutShippingSection.street}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="assertGuestStreet"/> + <seeInField selector="{{GuestCheckoutShippingSection.city}}" userInput="{{CustomerAddressSimple.city}}" stepKey="assertGuestCity"/> + <seeInField selector="{{GuestCheckoutShippingSection.region}}" userInput="{{CustomerAddressSimple.state}}" stepKey="assertGuestRegion"/> + <seeInField selector="{{GuestCheckoutShippingSection.postcode}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="assertGuestPostcode"/> + <seeInField selector="{{GuestCheckoutShippingSection.telephone}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="assertGuestTelephone"/> + </test> +</tests> From 0c0685459a5b8e7552af6a489efdb1e268b79084 Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Tue, 27 Nov 2018 16:53:37 +0200 Subject: [PATCH 28/88] MAGETWO-95779: Custom product attribute does not update when using Catalog Product Flat tables --- .../Indexer/Product/Flat/Action/Indexer.php | 35 +++---- .../Model/Indexer/Product/Flat/Action/Row.php | 12 ++- .../Indexer/Product/Flat/Action/RowTest.php | 8 +- .../Flat/Action/CustomFlatAttributeTest.php | 91 ++++++++++++++++++ .../Indexer/Product/Flat/Action/RowTest.php | 93 ++++++++++++------- ...t_simple_with_custom_attribute_in_flat.php | 79 ++++++++++++++++ ...with_custom_attribute_in_flat_rollback.php | 41 ++++++++ 7 files changed, 298 insertions(+), 61 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/CustomFlatAttributeTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat_rollback.php diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php index f95807f615390..25a9eebb5a0a9 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Indexer.php @@ -9,6 +9,7 @@ use Magento\Catalog\Api\Data\ProductInterface; use Magento\Framework\App\ResourceConnection; use Magento\Framework\EntityManager\MetadataPool; +use Magento\Store\Model\Store; /** * Class Indexer @@ -84,7 +85,7 @@ public function write($storeId, $productId, $valueFieldSuffix = '') [ 'entity_id' => 'e.entity_id', 'attribute_id' => 't.attribute_id', - 'value' => $this->_connection->getIfNullSql('`t2`.`value`', '`t`.`value`'), + 'value' => 't.value' ] ); @@ -99,32 +100,30 @@ public function write($storeId, $productId, $valueFieldSuffix = '') sprintf('e.%s = t.%s ', $linkField, $linkField) . $this->_connection->quoteInto( ' AND t.attribute_id IN (?)', array_keys($ids) - ) . ' AND t.store_id = 0', - [] - )->joinLeft( - ['t2' => $tableName], - sprintf('t.%s = t2.%s ', $linkField, $linkField) . - ' AND t.attribute_id = t2.attribute_id ' . - $this->_connection->quoteInto( - ' AND t2.store_id = ?', - $storeId - ), + ) . ' AND ' . $this->_connection->quoteInto('t.store_id IN(?)', [ + Store::DEFAULT_STORE_ID, + $storeId + ]), [] )->where( 'e.entity_id = ' . $productId - ); + )->order('t.store_id ASC'); $cursor = $this->_connection->query($select); while ($row = $cursor->fetch(\Zend_Db::FETCH_ASSOC)) { $updateData[$ids[$row['attribute_id']]] = $row['value']; $valueColumnName = $ids[$row['attribute_id']] . $valueFieldSuffix; if (isset($describe[$valueColumnName])) { - $valueColumns[$row['value']] = $valueColumnName; + $valueColumns[$row['attribute_id']] = [ + 'value' => $row['value'], + 'column_name' => $valueColumnName + ]; } } //Update not simple attributes (eg. dropdown) if (!empty($valueColumns)) { - $valueIds = array_keys($valueColumns); + $valueIds = array_column($valueColumns, 'value'); + $optionIdToAttributeName = array_column($valueColumns, 'column_name', 'value'); $select = $this->_connection->select()->from( ['t' => $this->_productIndexerHelper->getTable('eav_attribute_option_value')], @@ -133,14 +132,14 @@ public function write($storeId, $productId, $valueFieldSuffix = '') $this->_connection->quoteInto('t.option_id IN (?)', $valueIds) )->where( $this->_connection->quoteInto('t.store_id IN(?)', [ - \Magento\Store\Model\Store::DEFAULT_STORE_ID, + Store::DEFAULT_STORE_ID, $storeId ]) ) ->order('t.store_id ASC'); $cursor = $this->_connection->query($select); while ($row = $cursor->fetch(\Zend_Db::FETCH_ASSOC)) { - $valueColumnName = $valueColumns[$row['option_id']]; + $valueColumnName = $optionIdToAttributeName[$row['option_id']]; if (isset($describe[$valueColumnName])) { $updateData[$valueColumnName] = $row['value']; } @@ -150,6 +149,7 @@ public function write($storeId, $productId, $valueFieldSuffix = '') $columnNames = array_keys($columns); $columnNames[] = 'attribute_set_id'; $columnNames[] = 'type_id'; + $columnNames[] = $linkField; $select->from( ['e' => $entityTableName], $columnNames @@ -159,6 +159,7 @@ public function write($storeId, $productId, $valueFieldSuffix = '') $cursor = $this->_connection->query($select); $row = $cursor->fetch(\Zend_Db::FETCH_ASSOC); if (!empty($row)) { + $linkFieldId = $linkField; foreach ($row as $columnName => $value) { $updateData[$columnName] = $value; } @@ -170,7 +171,7 @@ public function write($storeId, $productId, $valueFieldSuffix = '') if (!empty($updateData)) { $updateData += ['entity_id' => $productId]; if ($linkField !== $metadata->getIdentifierField()) { - $updateData += [$linkField => $productId]; + $updateData += [$linkField => $linkFieldId]; } $updateFields = []; foreach ($updateData as $key => $value) { diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php index 6d0727259d9db..8ccd48f1360c0 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Action/Row.php @@ -95,15 +95,17 @@ public function execute($id = null) /* @var $status \Magento\Eav\Model\Entity\Attribute */ $status = $this->_productIndexerHelper->getAttribute(ProductInterface::STATUS); $statusTable = $status->getBackend()->getTable(); + $catalogProductEntityTable = $this->_productIndexerHelper->getTable('catalog_product_entity'); $statusConditions = [ - 'store_id IN(0,' . (int)$store->getId() . ')', - 'attribute_id = ' . (int)$status->getId(), - $linkField . ' = ' . (int)$id, + 's.store_id IN(0,' . (int)$store->getId() . ')', + 's.attribute_id = ' . (int)$status->getId(), + 'e.entity_id = ' . (int)$id, ]; $select = $this->_connection->select(); - $select->from($statusTable, ['value']) + $select->from(['e' => $catalogProductEntityTable], ['s.value']) ->where(implode(' AND ', $statusConditions)) - ->order('store_id DESC') + ->joinLeft(['s' => $statusTable], "e.{$linkField} = s.{$linkField}", []) + ->order('s.store_id DESC') ->limit(1); $result = $this->_connection->query($select); $status = $result->fetchColumn(0); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Action/RowTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Action/RowTest.php index f095867ed5c39..2de3b4ddf3f50 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Action/RowTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Action/RowTest.php @@ -100,10 +100,10 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); $this->connection->expects($this->any())->method('select')->willReturn($selectMock); - $selectMock->expects($this->any())->method('from')->with( - $attributeTable, - ['value'] - )->willReturnSelf(); + $selectMock->method('from') + ->willReturnSelf(); + $selectMock->method('joinLeft') + ->willReturnSelf(); $selectMock->expects($this->any())->method('where')->willReturnSelf(); $selectMock->expects($this->any())->method('order')->willReturnSelf(); $selectMock->expects($this->any())->method('limit')->willReturnSelf(); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/CustomFlatAttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/CustomFlatAttributeTest.php new file mode 100644 index 0000000000000..ceca81f232ff9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/CustomFlatAttributeTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Catalog\Model\Indexer\Product\Flat\Action; + +use Magento\TestFramework\Indexer\TestCase as IndexerTestCase; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Indexer\Product\Flat\Processor; +use Magento\Catalog\Model\ResourceModel\Product\Flat; +use Magento\Framework\Api\SearchCriteriaBuilder; + +/** + * Custom Flat Attribute Test + */ +class CustomFlatAttributeTest extends IndexerTestCase +{ + /** + * @var Processor + */ + private $processor; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->processor = $this->objectManager->get(Processor::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + } + + /** + * Tests that custom product attribute will appear in flat table and can be updated in it. + * + * @magentoDbIsolation disabled + * @magentoAppArea frontend + * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 + * @magentoDataFixture Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat.php + * + * @return void + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\StateException + */ + public function testProductUpdateCustomAttribute() + { + $product = $this->productRepository->get('simple_with_custom_flat_attribute'); + $product->setCustomAttribute('flat_attribute', 'changed flat attribute'); + $this->productRepository->save($product); + + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->objectManager->create(SearchCriteriaBuilder::class); + /** @var \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria */ + $searchCriteria = $searchCriteriaBuilder->addFilter('sku', 'simple_with_custom_flat_attribute') + ->create(); + + $items = $this->productRepository->getList($searchCriteria) + ->getItems(); + $product = reset($items); + $resourceModel = $product->getResourceCollection() + ->getEntity(); + + self::assertInstanceOf( + Flat::class, + $resourceModel, + 'Product should be received from flat resource' + ); + + self::assertEquals( + 'changed flat attribute', + $product->getFlatAttribute(), + 'Product flat attribute should be able to change.' + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php index 15c90891878a0..67c81772462d6 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Indexer/Product/Flat/Action/RowTest.php @@ -3,87 +3,110 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Model\Indexer\Product\Flat\Action; +use Magento\TestFramework\Indexer\TestCase as IndexerTestCase; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Indexer\Product\Flat\Processor; +use Magento\Catalog\Block\Product\ListProduct; +use Magento\Catalog\Api\CategoryRepositoryInterface; + /** * Class RowTest */ -class RowTest extends \Magento\TestFramework\Indexer\TestCase +class RowTest extends IndexerTestCase { /** - * @var \Magento\Catalog\Model\Product + * @var Processor */ - protected $_product; + private $processor; /** - * @var \Magento\Catalog\Model\Category + * @var \Magento\Framework\ObjectManagerInterface */ - protected $_category; + private $objectManager; /** - * @var \Magento\Catalog\Model\Indexer\Product\Flat\State + * @var ProductRepositoryInterface */ - protected $_state; + private $productRepository; /** - * @var \Magento\Catalog\Model\Indexer\Product\Flat\Processor + * @var CategoryRepositoryInterface */ - protected $_processor; + private $categoryRepository; + /** + * @inheritdoc + */ protected function setUp() { - $this->_product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Product::class - ); - $this->_category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Category::class - ); - $this->_processor = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Indexer\Product\Flat\Processor::class - ); + $this->objectManager = Bootstrap::getObjectManager(); + $this->processor = $this->objectManager->get(Processor::class); + $this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class); + $this->categoryRepository = $this->objectManager->get(CategoryRepositoryInterface::class); } /** + * Tests product update + * * @magentoDbIsolation disabled * @magentoDataFixture Magento/Catalog/_files/row_fixture.php * @magentoConfigFixture current_store catalog/frontend/flat_catalog_product 1 * @magentoAppArea frontend + * + * @return void + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\StateException */ public function testProductUpdate() { - $categoryFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Catalog\Model\CategoryFactory::class); - $listProduct = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->create(\Magento\Catalog\Block\Product\ListProduct::class); + /** @var ListProduct $listProduct */ + $listProduct = $this->objectManager->create(ListProduct::class); - $this->_processor->getIndexer()->setScheduled(false); - $this->assertFalse( - $this->_processor->getIndexer()->isScheduled(), + $this->processor->getIndexer() + ->setScheduled(false); + $isScheduled = $this->processor->getIndexer() + ->isScheduled(); + self::assertFalse( + $isScheduled, 'Indexer is in scheduled mode when turned to update on save mode' ); - $this->_product->load(1); - $this->_product->setName('Updated Product'); - $this->_product->save(); + $this->processor->reindexAll(); - $this->_processor->reindexAll(); - - $category = $categoryFactory->create()->load(9); + $product = $this->productRepository->get('simple'); + $product->setName('Updated Product'); + $this->productRepository->save($product); + + /** @var \Magento\Catalog\Api\Data\CategoryInterface $category */ + $category = $this->categoryRepository->get(9); + /** @var \Magento\Catalog\Model\Layer $layer */ $layer = $listProduct->getLayer(); $layer->setCurrentCategory($category); /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection */ $productCollection = $layer->getProductCollection(); - $this->assertTrue( + self::assertTrue( $productCollection->isEnabledFlat(), 'Product collection is not using flat resource when flat is on' ); - $this->assertEquals(2, $productCollection->count(), 'Product collection items count must be exactly 2'); + self::assertEquals( + 2, + $productCollection->count(), + 'Product collection items count must be exactly 2' + ); foreach ($productCollection as $product) { /** @var $product \Magento\Catalog\Model\Product */ - if ($product->getId() == 1) { - $this->assertEquals( + if ($product->getSku() === 'simple') { + self::assertEquals( 'Updated Product', $product->getName(), 'Product name from flat does not match with updated name' diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat.php new file mode 100644 index 0000000000000..2b1b271a8bb3c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\ProductFactory; +use Magento\Catalog\Api\Data\ProductAttributeInterface; +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; +use Magento\Catalog\Model\Indexer\Product\Flat\Processor; +use Magento\Catalog\Setup\CategorySetup; +use Magento\Eav\Model\Entity; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Type; + +/** @var \Magento\TestFramework\ObjectManager $objectManager */ +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var ProductFactory $productFactory */ +$productFactory = $objectManager->get(ProductFactory::class); +/** @var ProductAttributeRepositoryInterface $attributeRepository */ +$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class); + + +/** @var $installer CategorySetup */ +$installer = $objectManager->create(CategorySetup::class); +$entityModel = $objectManager->create(Entity::class); +$attributeSetId = $installer->getAttributeSetId(Product::ENTITY, 'Default'); +$entityTypeId = $entityModel->setType(Product::ENTITY) + ->getTypeId(); +$groupId = $installer->getDefaultAttributeGroupId($entityTypeId, $attributeSetId); + +/** @var ProductAttributeInterface $attribute */ +$attribute = $objectManager->create(ProductAttributeInterface::class); + +$attribute->setAttributeCode('flat_attribute') + ->setEntityTypeId($entityTypeId) + ->setIsVisible(true) + ->setFrontendInput('text') + ->setIsFilterable(1) + ->setIsUserDefined(1) + ->setUsedInProductListing(1) + ->setBackendType('varchar') + ->setIsUsedInGrid(1) + ->setIsVisibleInGrid(1) + ->setIsFilterableInGrid(1) + ->setFrontendLabel('nobody cares') + ->setAttributeGroupId($groupId) + ->setAttributeSetId(4); + +$attributeRepository->save($attribute); + +/** @var Processor $processor */ +$processor = $objectManager->create(Processor::class); +$scheduled = $processor->getIndexer() + ->isScheduled(); +$processor->reindexAll(); + +$product = $productFactory->create() + ->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setName('Simple With Attribute That Used In Flat') + ->setSku('simple_with_custom_flat_attribute') + ->setPrice(100) + ->setVisibility(1) + ->setStockData( + [ + 'use_config_manage_stock' => 1, + 'qty' => 100, + 'is_in_stock' => 1, + ] + ) + ->setStatus(1); +$product->setCustomAttribute('flat_attribute', 'flat attribute value'); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat_rollback.php new file mode 100644 index 0000000000000..c1892d504ecc3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple_with_custom_attribute_in_flat_rollback.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +use Magento\Framework\Registry; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; + +/** @var Magento\Framework\ObjectManagerInterface $objectManager */ +$objectManager = Bootstrap::getObjectManager(); +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +/** @var ProductAttributeRepositoryInterface $attributeRepository */ +$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class); +/** @var Registry $registry */ +$registry = $objectManager->get(Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +try { + /** @var \Magento\Catalog\Api\Data\ProductInterface $product */ + $product = $productRepository->get('simple_with_custom_flat_attribute'); + $productRepository->delete($product); +} catch (NoSuchEntityException $e) { +} + +try { + /** @var \Magento\Catalog\Api\Data\ProductAttributeInterface $attribute */ + $attribute = $attributeRepository->get('flat_attribute'); + $attributeRepository->delete($attribute); +} catch (NoSuchEntityException $e) { +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From 2f89ed74a963f507f076d4e3b0d77eba33837c9f Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Wed, 28 Nov 2018 08:57:00 +0200 Subject: [PATCH 29/88] MAGETWO-89397: Wrong Checkout Totals Sort Order in cart --- .../Magento/Sales/Test/Mftf/Data/SalesConfigData.xml | 4 ++-- .../Sales/Test/Mftf/Metadata/sales_config-meta.xml | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml b/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml index 3a8449caae643..6b97c4e13caea 100644 --- a/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml +++ b/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="EnabledMinimumOrderAmount500" type="sales_groups"> + <entity name="EnabledMinimumOrderAmount500" type="sales_minimum_order"> <requiredEntity type="active">EnableMinimumOrderCheck</requiredEntity> <requiredEntity type="amount">MinimumOrderAmount500</requiredEntity> </entity> @@ -18,7 +18,7 @@ <data key="value">500</data> </entity> - <entity name="DisabledMinimumOrderAmount" type="sales_groups"> + <entity name="DisabledMinimumOrderAmount" type="sales_minimum_order"> <requiredEntity type="active">DisableMinimumOrderCheck</requiredEntity> </entity> <entity name="DisableMinimumOrderCheck" type="active"> diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml index e676ca89a422e..2ec7577bbf867 100644 --- a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml @@ -42,12 +42,6 @@ <object key="grand_total" dataType="grand_total"> <field key="value">integer</field> </object> - <object key="giftcardaccount" dataType="giftcardaccount"> - <field key="value">integer</field> - </object> - <object key="customerbalance" dataType="customerbalance"> - <field key="value">integer</field> - </object> </object> </object> </object> @@ -86,12 +80,6 @@ <field key="value">integer</field> </object> </object> - <object key="giftcardaccount" dataType="giftcardaccount"> - <field key="value">integer</field> - </object> - <object key="customerbalance" dataType="customerbalance"> - <field key="value">integer</field> - </object> </object> </object> </object> From dd8bf8519f0cdffd5c3001406c37e4c3fe505091 Mon Sep 17 00:00:00 2001 From: Stas Kozar <stas.kozar@transoftgroup.com> Date: Wed, 28 Nov 2018 11:09:48 +0200 Subject: [PATCH 30/88] MAGETWO-95067: Checkout data (shipping address etc) not persistant after cart update --- .../Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml index 2185c8de45c73..bebb7be6c9b15 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontGuestCheckoutDataPersistTest.xml @@ -40,11 +40,11 @@ <argument name="shippingMethod" value="Flat Rate"/> </actionGroup> <!-- Add simple product to cart --> - <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart2"> + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart1"> <argument name="product" value="$$createProduct$$"/> </actionGroup> <!-- Navigate to checkout --> - <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart2"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart1"/> <seeInField selector="{{GuestCheckoutShippingSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="assertGuestEmail"/> <seeInField selector="{{GuestCheckoutShippingSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="assertGuestFirstName"/> <seeInField selector="{{GuestCheckoutShippingSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="assertGuestLastName"/> From c83efca2a13bf8b2eefb7286edf388c842662fb0 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 28 Nov 2018 11:29:48 +0200 Subject: [PATCH 31/88] MAGETWO-87734: [Sigma Beauty]Cannot pause Youtube video in IE 11 --- .../AdminProductVideoActionGroup.xml | 46 +++++++++ .../StorefrontProductVideoActionGroup.xml | 17 ++++ .../Test/Mftf/Data/ProductVideoConfigData.xml | 26 +++++ .../Test/Mftf/Data/ProductVideoData.xml | 16 +++ .../Metadata/product_video_config-meta.xml | 21 ++++ .../Test/Mftf/Page/AdminProductCreatePage.xml | 14 +++ .../Section/AdminProductImagesSection.xml | 16 +++ .../Section/AdminProductNewVideoSection.xml | 17 ++++ .../StorefrontProductInfoMainSection.xml | 18 ++++ ...ontYoutubeVideoWindowOnProductPageTest.xml | 97 +++++++++++++++++++ lib/web/fotorama/fotorama.js | 17 ++-- 11 files changed, 298 insertions(+), 7 deletions(-) create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AdminProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/StorefrontProductVideoActionGroup.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoConfigData.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoData.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Metadata/product_video_config-meta.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductImagesSection.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductNewVideoSection.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml create mode 100644 app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AdminProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AdminProductVideoActionGroup.xml new file mode 100644 index 0000000000000..621caea0cfc6d --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/AdminProductVideoActionGroup.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!-- Add video in Admin Product page --> + <actionGroup name="addProductVideo"> + <arguments> + <argument name="video" defaultValue="mftfTestProductVideo"/> + </arguments> + + <scrollTo selector="{{AdminProductImagesSection.productImagesToggle}}" x="0" y="-100" stepKey="scrollToArea"/> + <conditionalClick selector="{{AdminProductImagesSection.productImagesToggle}}" + dependentSelector="{{AdminProductImagesSection.imageUploadButton}}" + visible="false" + stepKey="openProductVideoSection"/> + <waitForElementVisible selector="{{AdminProductImagesSection.addVideoButton}}" stepKey="waitForAddVideoButtonVisible"/> + <click selector="{{AdminProductImagesSection.addVideoButton}}" stepKey="addVideo"/> + <waitForElementVisible selector="{{AdminProductNewVideoSection.videoUrlTextField}}" stepKey="waitForUrlElementVisible"/> + <fillField selector="{{AdminProductNewVideoSection.videoUrlTextField}}" userInput="{{video.videoUrl}}" stepKey="fillFieldVideoUrl"/> + <fillField selector="{{AdminProductNewVideoSection.videoTitleTextField}}" userInput="{{video.videoTitle}}" stepKey="fillFieldVideoTitle"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <waitForElementNotVisible selector="{{AdminProductNewVideoSection.saveButtonDisabled}}" wait="30" stepKey="waitForSaveButtonVisible"/> + <click selector="{{AdminProductNewVideoSection.saveButton}}" stepKey="saveVideo"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappear"/> + </actionGroup> + + <!-- Assert product video in Admin Product page --> + <actionGroup name="assertProductVideoAdminProductPage"> + <arguments> + <argument name="video" defaultValue="mftfTestProductVideo"/> + </arguments> + <scrollTo selector="{{AdminProductImagesSection.productImagesToggle}}" x="0" y="-100" stepKey="scrollToArea"/> + <conditionalClick selector="{{AdminProductImagesSection.productImagesToggle}}" + dependentSelector="{{AdminProductImagesSection.imageUploadButton}}" + visible="false" + stepKey="openProductVideoSection"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <seeElement selector="{{AdminProductImagesSection.videoTitleText(video.videoShortTitle)}}" stepKey="seeVideoTitle"/> + <seeElementInDOM selector="{{AdminProductImagesSection.videoUrlHiddenField(video.videoUrl)}}" stepKey="seeVideoItem"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/StorefrontProductVideoActionGroup.xml b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/StorefrontProductVideoActionGroup.xml new file mode 100644 index 0000000000000..28634f41deec1 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/ActionGroup/StorefrontProductVideoActionGroup.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!--Assert product video in Storefront Product page --> + <actionGroup name="assertProductVideoStorefrontProductPage"> + <arguments> + <argument name="dataTypeAttribute" defaultValue="'youtube'"/> + </arguments> + <seeElement selector="{{StorefrontProductInfoMainSection.productVideo(dataTypeAttribute)}}" stepKey="seeProductVideoDataType"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoConfigData.xml b/app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoConfigData.xml new file mode 100644 index 0000000000000..8fe5899e91ef8 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoConfigData.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <!-- mftf test youtube api key configuration --> + <entity name="ProductVideoYoutubeApiKeyConfig" type="product_video_config"> + <requiredEntity type="youtube_api_key_config">YouTubeApiKey</requiredEntity> + </entity> + <entity name="YouTubeApiKey" type="youtube_api_key_config"> + <data key="value">AIzaSyDwqDWuw1lra-LnpJL2Mr02DYuFmkuRSns</data> + </entity> + + <!-- default configuration used to restore Magento config --> + <entity name="DefaultProductVideoConfig" type="product_video_config"> + <requiredEntity type="youtube_api_key_config">DefaultYouTubeApiKey</requiredEntity> + </entity> + <entity name="DefaultYouTubeApiKey" type="youtube_api_key_config"> + <data key="value"/> + </entity> +</entities> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoData.xml b/app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoData.xml new file mode 100644 index 0000000000000..5bc4ad86e0f06 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Data/ProductVideoData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="mftfTestProductVideo" type="product_video"> + <data key="videoUrl">https://youtu.be/bpOSxM0rNPM</data> + <data key="videoTitle">Arctic Monkeys - Do I Wanna Know? (Official Video)</data> + <data key="videoShortTitle">Arctic Monkeys</data> + </entity> +</entities> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Metadata/product_video_config-meta.xml b/app/code/Magento/ProductVideo/Test/Mftf/Metadata/product_video_config-meta.xml new file mode 100644 index 0000000000000..dc6d3af1c52c5 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Metadata/product_video_config-meta.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateProductVideoYouTubeApiKeyConfig" dataType="product_video_config" type="create" auth="adminFormKey" url="admin/system_config/save/section/catalog/" method="POST" successRegex="/messages-message-success/"> + <object key="groups" dataType="product_video_config"> + <object key="product_video" dataType="product_video_config"> + <object key="fields" dataType="product_video_config"> + <object key="youtube_api_key" dataType="youtube_api_key_config"> + <field key="value">string</field> + </object> + </object> + </object> + </object> + </operation> +</operations> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml b/app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml new file mode 100644 index 0000000000000..070d1fd15c458 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminProductCreatePage" url="catalog/product/new/set/{{set}}/type/{{type}}/" area="admin" module="Magento_Catalog" parameterized="true"> + <section name="AdminProductNewVideoSection"/> + </page> +</pages> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductImagesSection.xml b/app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductImagesSection.xml new file mode 100644 index 0000000000000..913ae8c955340 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductImagesSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminProductImagesSection"> + <element name="addVideoButton" type="button" selector="#add_video_button" timeout="60"/> + <element name="videoUrlHiddenField" type="text" selector="#media_gallery_content input[value*='{{title}}']" parameterized="true"/> + <element name="videoTitleText" type="text" selector="//*[@id='media_gallery_content']//div[contains(text(), '{{title}}')]" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductNewVideoSection.xml b/app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductNewVideoSection.xml new file mode 100644 index 0000000000000..8df254aea7c50 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Section/AdminProductNewVideoSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminProductNewVideoSection"> + <element name="saveButton" type="button" selector=".action-primary.video-create-button" timeout="30"/> + <element name="saveButtonDisabled" type="text" selector="button.action-primary.video-create-button[disabled='disabled']"/> + <element name="videoUrlTextField" type="input" selector="#video_url"/> + <element name="videoTitleTextField" type="input" selector="#video_title"/> + </section> +</sections> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml new file mode 100644 index 0000000000000..1ce56ff4996ab --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Section/StorefrontProductInfoMainSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontProductInfoMainSection"> + <element name="productVideo" type="text" selector=".product-video[data-type='{{videoType}}']" parameterized="true"/> + <element name="clickInVideo" type="video" selector=".fotorama__stage__shaft"/> + <element name="videoPausedMode" type="video" selector="[class*='paused-mode']"/> + <element name="videoPlayedMode" type="video" selector="[class*='playing-mode']"/> + <element name="frameVideo" type="video" selector="widget2"/> + </section> +</sections> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml b/app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml new file mode 100644 index 0000000000000..bc98329121955 --- /dev/null +++ b/app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml @@ -0,0 +1,97 @@ +<?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="StorefrontYoutubeVideoWindowOnProductPageTest"> + <annotations> + <features value="ProductVideo"/> + <stories value="MAGETWO-87734: [Sigma Beauty]Cannot pause Youtube video in IE 11"/> + <testCaseId value="MAGETWO-96677"/> + <title value="Youtube video window on the product page"/> + <description value="Check Youtube video window on the product page"/> + <severity value="MAJOR"/> + <group value="productVideo"/> + </annotations> + + <before> + <!--Log In--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <!--Create category--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <!--Create product--> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!-- Set product video Youtube api key configuration --> + <createData entity="ProductVideoYoutubeApiKeyConfig" stepKey="setStoreConfig"/> + </before> + + <after> + <!--Clear all filters on products grid page--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="goToProductsIndex"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearExistingProductFilters"/> + <!--Delete created product and category--> + <deleteData createDataKey="createProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategoryFirst"/> + <!-- Set product video configuration to default --> + <createData entity="DefaultProductVideoConfig" stepKey="setStoreDefaultConfig"/> + <!--Log Out--> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open simple product--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="goToProductIndex"/> + <waitForPageLoad stepKey="wait1"/> + <actionGroup ref="AdminGridFilterSearchResultsByInput" stepKey="filterProductGridBySku"> + <argument name="inputName" value="sku"/> + <argument name="value" value="$$createProduct.sku$$"/> + </actionGroup> + <click selector="{{AdminDataGridTableSection.firstRow}}" stepKey="openFirstProductForEdit"/> + <waitForPageLoad stepKey="waitProductPageIsLoaded"/> + + <!-- Add product video --> + <actionGroup ref="addProductVideo" stepKey="addProductVideo"/> + <!-- Assert product video in admin product form --> + <actionGroup ref="assertProductVideoAdminProductPage" stepKey="assertProductVideoAdminProductPage"/> + + <!-- Save the product --> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + <waitForPageLoad stepKey="waitForProductSaved"/> + + <!-- Assert product video in storefront product page --> + <amOnPage url="{{StorefrontProductPage.url($$createProduct.name$$)}}" stepKey="goToStorefrontProductPage"/> + <waitForPageLoad stepKey="waitForStorefrontProductPageLoaded"/> + <actionGroup ref="assertProductVideoStorefrontProductPage" stepKey="assertProductVideoStorefrontProductPage"/> + + <!--Click Play video button--> + <click selector="{{StorefrontProductInfoMainSection.clickInVideo}}" stepKey="clickToPlayVideo"/> + <wait time="5" stepKey="waitFiveSecondToPlayVideo"/> + <switchToIFrame selector="{{StorefrontProductInfoMainSection.frameVideo}}" stepKey="switchToFrame"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="waitForVideoPlayed"/> + <seeElement selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="assertVideoIsPlayed"/> + <switchToIFrame stepKey="switchBack"/> + + <!--Click Pause button--> + <click selector="{{StorefrontProductInfoMainSection.clickInVideo}}" stepKey="clickToStopVideo"/> + <wait time="5" stepKey="waitFiveSecondToStopVideo"/> + <switchToIFrame selector="{{StorefrontProductInfoMainSection.frameVideo}}" stepKey="switchToFrame1"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.videoPausedMode}}" stepKey="waitForVideoPaused"/> + <seeElement selector="{{StorefrontProductInfoMainSection.videoPausedMode}}" stepKey="assertVideoIsPaused"/> + <switchToIFrame stepKey="switchBack1"/> + + <!--Click Play video button again. Make sure that Video continued playing--> + <click selector="{{StorefrontProductInfoMainSection.clickInVideo}}" stepKey="clickAgainToPlayVideo"/> + <wait time="5" stepKey="waitAgainFiveSecondToPlayVideo"/> + <switchToIFrame selector="{{StorefrontProductInfoMainSection.frameVideo}}" stepKey="switchToFrame2"/> + <waitForElementVisible selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="waitForVideoPlayedAgain"/> + <seeElement selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="AssertVideoIsPlayedAgain"/> + <switchToIFrame stepKey="switchBack2"/> + </test> +</tests> + diff --git a/lib/web/fotorama/fotorama.js b/lib/web/fotorama/fotorama.js index 4062c501cb798..4f323e4312f6b 100644 --- a/lib/web/fotorama/fotorama.js +++ b/lib/web/fotorama/fotorama.js @@ -2481,11 +2481,11 @@ fotoramaVersion = '4.6.4'; .append($videoPlay.clone()); // This solves tabbing problems - addFocus(frame, function () { + addFocus(frame, function (e) { setTimeout(function () { lockScroll($stage); }, 0); - clickToShow({index: frameData.eq, user: true}); + clickToShow({index: frameData.eq, user: true}, e); }); $stageFrame = $stageFrame.add($frame); @@ -3034,7 +3034,10 @@ fotoramaVersion = '4.6.4'; return time; } - that.showStage = function (silent, options, time) { + that.showStage = function (silent, options, time, e) { + if (e !== undefined && e.target.tagName == 'IFRAME') { + return; + } unloadVideo($videoPlaying, activeFrame.i !== data[normalizeIndex(repositionIndex)].i); frameDraw(activeIndexes, 'stage'); stageFramePosition(SLOW ? [dirtyIndex] : [dirtyIndex, getPrevIndex(dirtyIndex), getNextIndex(dirtyIndex)]); @@ -3122,7 +3125,7 @@ fotoramaVersion = '4.6.4'; } }; - that.show = function (options) { + that.show = function (options, e) { that.longPress.singlePressInProgress = true; var index = calcActiveIndex(options); @@ -3133,7 +3136,7 @@ fotoramaVersion = '4.6.4'; var silent = _activeFrame === activeFrame && !options.user; - that.showStage(silent, options, time); + that.showStage(silent, options, time, e); that.showNav(silent, options, time); showedFLAG = typeof lastActiveIndex !== 'undefined' && lastActiveIndex !== activeIndex; @@ -3493,7 +3496,7 @@ fotoramaVersion = '4.6.4'; $stage.on('mousemove', stageCursor); - function clickToShow(showOptions) { + function clickToShow(showOptions, e) { clearTimeout(clickToShow.t); if (opts.clicktransition && opts.clicktransition !== opts.transition) { @@ -3510,7 +3513,7 @@ fotoramaVersion = '4.6.4'; }, 10); }, 0); } else { - that.show(showOptions); + that.show(showOptions, e); } } From 540f51c63e2bcf97c38a83b755028ff15e4aa50d Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 28 Nov 2018 13:40:09 +0200 Subject: [PATCH 32/88] MAGETWO-96141: "Custom price" can't be removed during order creation in admin --- .../quote_with_custom_price_rollback.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php index ccfd4a0768709..d17ec28063543 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_custom_price_rollback.php @@ -4,3 +4,21 @@ * See COPYING.txt for license details. */ include __DIR__ . '/quote_rollback.php'; + +/** @var \Magento\Framework\Registry $registry */ +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + +try { + $product = $productRepository->get('simple_quote_custom_price', false, null, true); + $productRepository->delete($product); +} catch (\Magento\Framework\Exception\NoSuchEntityException $exception) { + //Product already removed +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From b3bfef59dd1413e666a7d178c45d1f6694a0f850 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Wed, 28 Nov 2018 04:12:15 -0800 Subject: [PATCH 33/88] MAGETWO-95535: [Magento cloud] - Images revert to default placeholder on import --- .../Model/Import/Product.php | 1 + .../Model/Import/ProductTest.php | 31 +++++++++++++++++++ .../import_media_non_existing_images.csv | 2 ++ 3 files changed, 34 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_non_existing_images.csv diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 84fa13e6599d9..f9c50ff62a0f9 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1735,6 +1735,7 @@ protected function _saveProducts() if ($uploadedFile) { $uploadedImages[$columnImage] = $uploadedFile; } else { + unset($rowData[$column]); $this->addRowError( ValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE, $rowNum, diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index f3cb01a9bbe2e..1e4b6ba60d596 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -2354,4 +2354,35 @@ public function testImportProductWithUpdateUrlKey() $collUrlRewrite->getFirstItem()->getRequestPath() ); } + + /** + * Test that product import with non existing images does not broke roles on existing images. + * + * @magentoDataIsolation enabled + * @magentoDataFixture mediaImportImageFixture + * @magentoAppIsolation enabled + */ + public function testSaveProductOnImportNonExistingImage() + { + $this->importDataForMediaTest('import_media.csv'); + + $product = $this->getProductBySku('simple_new'); + + $this->assertEquals('/m/a/magento_image.jpg', $product->getData('image')); + $this->assertEquals('/m/a/magento_small_image.jpg', $product->getData('small_image')); + $this->assertEquals('/m/a/magento_thumbnail.jpg', $product->getData('thumbnail')); + $this->assertEquals('/m/a/magento_image.jpg', $product->getData('swatch_image')); + + $this->importDataForMediaTest('import_media_non_existing_images.csv', 1); + + $this->assertNotEquals('/u/p/uploaded.jpg', $product->getData('image')); + $this->assertNotEquals('/u/p/uploaded.jpg', $product->getData('small_image')); + $this->assertNotEquals('/u/p/uploaded.jpg', $product->getData('thumbnail')); + $this->assertNotEquals('/u/p/uploaded.jpg', $product->getData('swatch_image')); + + $this->assertEquals('/m/a/magento_image.jpg', $product->getData('image')); + $this->assertEquals('/m/a/magento_small_image.jpg', $product->getData('small_image')); + $this->assertEquals('/m/a/magento_thumbnail.jpg', $product->getData('thumbnail')); + $this->assertEquals('/m/a/magento_image.jpg', $product->getData('swatch_image')); + } } diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_non_existing_images.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_non_existing_images.csv new file mode 100644 index 0000000000000..99fdf641d9a33 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/import_media_non_existing_images.csv @@ -0,0 +1,2 @@ +sku,store_view_code,attribute_set_code,product_type,categories,product_websites,name,description,short_description,weight,product_online,tax_class_name,visibility,price,special_price,special_price_from_date,special_price_to_date,url_key,meta_title,meta_keywords,meta_description,base_image,base_image_label,small_image,small_image_label,thumbnail_image,thumbnail_image_label,swatch_image,swatch_image_label1,created_at,updated_at,new_from_date,new_to_date,display_product_options_in,map_price,msrp_price,map_enabled,gift_message_available,custom_design,custom_design_from,custom_design_to,custom_layout_update,page_layout,product_options_container,msrp_display_actual_price_type,country_of_manufacture,additional_attributes,qty,out_of_stock_qty,use_config_min_qty,is_qty_decimal,allow_backorders,use_config_backorders,min_cart_qty,use_config_min_sale_qty,max_cart_qty,use_config_max_sale_qty,is_in_stock,notify_on_stock_below,use_config_notify_stock_qty,manage_stock,use_config_manage_stock,use_config_qty_increments,qty_increments,use_config_enable_qty_inc,enable_qty_increments,is_decimal_divided,website_id,related_skus,crosssell_skus,upsell_skus,additional_images,additional_image_labels,hide_from_product_page,custom_options,bundle_price_type,bundle_sku_type,bundle_price_view,bundle_weight_type,bundle_values,associated_skus +simple_new,,Default,simple,,base,New Product,,,,1,Taxable Goods,"Catalog, Search",10,,,,new-product,New Product,New Product,New Product,/u/p/uploaded.jpg,Image Label,/u/p/uploaded.jpg,Small Image Label,/u/p/uploaded.jpg,Thumbnail Label,magento_image.jpg,Image Label,10/20/15 07:05,10/20/15 07:05,,,Block after Info Column,,,,,,,,,,,,,"has_options=1,quantity_and_stock_status=In Stock,required_options=1",100,0,1,0,0,1,1,1,10000,1,1,1,1,1,0,1,1,0,0,0,1,,,,"magento_additional_image_one.jpg, magento_additional_image_two.jpg","Additional Image Label One,Additional Image Label Two",,,,,,,, From a14f56172a95dcf7a46321a7e8cbef8cc20b033d Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Wed, 28 Nov 2018 05:48:49 -0800 Subject: [PATCH 34/88] MAGETWO-85037: In Related product section add to wishlist and compare is not displaying for mobile devices portrait view --- .../blank/Magento_Catalog/web/css/source/module/_listings.less | 1 - .../luma/Magento_Catalog/web/css/source/module/_listings.less | 1 - 2 files changed, 2 deletions(-) diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less index 8b727b0d9c28d..951ca89a07988 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_listings.less @@ -63,7 +63,6 @@ } &-actions { - display: none; .actions-secondary { > button.action { diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less index d0382d34d39fc..6bf766b7400a7 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_listings.less @@ -68,7 +68,6 @@ } &-actions { - display: none; .actions-secondary { > button.action { From 83bb1efae42d5333553c750c6b2e342fd1b5edb0 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Wed, 28 Nov 2018 16:00:12 +0200 Subject: [PATCH 35/88] MAGETWO-87734: [Sigma Beauty]Cannot pause Youtube video in IE 11 --- .../ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml | 2 +- .../Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml b/app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml index 070d1fd15c458..52f13a1da5188 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/Page/AdminProductCreatePage.xml @@ -7,7 +7,7 @@ --> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="AdminProductCreatePage" url="catalog/product/new/set/{{set}}/type/{{type}}/" area="admin" module="Magento_Catalog" parameterized="true"> <section name="AdminProductNewVideoSection"/> </page> diff --git a/app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml b/app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml index bc98329121955..15888d1af8ee5 100644 --- a/app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml +++ b/app/code/Magento/ProductVideo/Test/Mftf/Test/StorefrontYoutubeVideoWindowOnProductPageTest.xml @@ -47,7 +47,6 @@ <!--Open simple product--> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="goToProductIndex"/> - <waitForPageLoad stepKey="wait1"/> <actionGroup ref="AdminGridFilterSearchResultsByInput" stepKey="filterProductGridBySku"> <argument name="inputName" value="sku"/> <argument name="value" value="$$createProduct.sku$$"/> @@ -66,7 +65,6 @@ <!-- Assert product video in storefront product page --> <amOnPage url="{{StorefrontProductPage.url($$createProduct.name$$)}}" stepKey="goToStorefrontProductPage"/> - <waitForPageLoad stepKey="waitForStorefrontProductPageLoaded"/> <actionGroup ref="assertProductVideoStorefrontProductPage" stepKey="assertProductVideoStorefrontProductPage"/> <!--Click Play video button--> @@ -90,7 +88,7 @@ <wait time="5" stepKey="waitAgainFiveSecondToPlayVideo"/> <switchToIFrame selector="{{StorefrontProductInfoMainSection.frameVideo}}" stepKey="switchToFrame2"/> <waitForElementVisible selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="waitForVideoPlayedAgain"/> - <seeElement selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="AssertVideoIsPlayedAgain"/> + <seeElement selector="{{StorefrontProductInfoMainSection.videoPlayedMode}}" stepKey="assertVideoIsPlayedAgain"/> <switchToIFrame stepKey="switchBack2"/> </test> </tests> From ee85879dae466ede8892da29c0fb136633449f06 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Thu, 29 Nov 2018 09:53:24 +0200 Subject: [PATCH 36/88] MAGETWO-95556: Zoomed part of images becomes distorted in case when image width/height ratio has ~2x difference - Changed the logic of calculating the coefficient of zoom --- lib/web/mage/gallery/gallery.less | 1 + lib/web/magnifier/magnifier.js | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/web/mage/gallery/gallery.less b/lib/web/mage/gallery/gallery.less index f551157210692..fb95d3d1ed98c 100644 --- a/lib/web/mage/gallery/gallery.less +++ b/lib/web/mage/gallery/gallery.less @@ -768,6 +768,7 @@ max-width: inherit; position: absolute; top: 0; + object-fit: scale-down; } } diff --git a/lib/web/magnifier/magnifier.js b/lib/web/magnifier/magnifier.js index 0807a4c394995..f6ea1300e77ea 100644 --- a/lib/web/magnifier/magnifier.js +++ b/lib/web/magnifier/magnifier.js @@ -542,7 +542,11 @@ showWrapper = true; bindEvents(eventType, thumb); data[idx].status = 2; - data[idx].zoom = largeObj.height / largeWrapper.height(); + if (largeObj.width > largeObj.height) { + data[idx].zoom = largeObj.width / largeWrapper.width(); + } else { + data[idx].zoom = largeObj.height / largeWrapper.height(); + } setThumbData(thumb, data[idx]); updateLensOnLoad(idx, thumb, largeObj, largeWrapper); } From 90d4fe6258dd9aff13b23beda6c7c3d2fda6a9fd Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Thu, 29 Nov 2018 10:56:03 +0200 Subject: [PATCH 37/88] MAGETWO-89397: Wrong Checkout Totals Sort Order in cart --- ...rontCheckoutTotalsSortOrderInCartTest.xml} | 26 +++++----- .../Sales/Test/Mftf/Data/SalesConfigData.xml | 12 +++-- .../Test/Mftf/Metadata/sales_config-meta.xml | 52 ++++++------------- .../StorefrontSalesRuleActionGroup.xml | 6 --- 4 files changed, 39 insertions(+), 57 deletions(-) rename app/code/Magento/Checkout/Test/Mftf/Test/{CheckoutTotalsSortOrderInCartTest.xml => StorefrontCheckoutTotalsSortOrderInCartTest.xml} (60%) diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml similarity index 60% rename from app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml rename to app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml index 1368062bddd2c..872ee9fb16ff5 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/CheckoutTotalsSortOrderInCartTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml @@ -6,7 +6,7 @@ */ --> <tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> - <test name="CheckoutTotalsSortOrderInCartTest"> + <test name="StorefrontCheckoutTotalsSortOrderInCartTest"> <annotations> <title value="Checkout Totals Sort Order configuration and displaying in cart"/> <stories value="MAGETWO-89397: Wrong Checkout Totals Sort Order in cart"/> @@ -18,24 +18,26 @@ </annotations> <before> - <createData entity="_defaultCategory" stepKey="defaultCategory"/> - <createData entity="SimpleProduct" stepKey="simpleProduct"> - <requiredEntity createDataKey="defaultCategory"/> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> </createData> - <createData entity="ApiCartRule1" stepKey="cartRule"/> + <createData entity="ApiCartRule1" stepKey="createCartRule"/> <createData entity="CheckoutShippingTotalsSortOrder" stepKey="setConfigShippingTotalsSortOrder"/> </before> <after> - <createData entity="DefaultCheckoutTotalsSortOrder" stepKey="setDefaultTotalsSortOrder"/> - <deleteData createDataKey="cartRule" stepKey="deleteCartRule"/> - <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> - <deleteData createDataKey="defaultCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createCartRule" stepKey="deleteCartRule"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <createData entity="DefaultTotalsSortOrder" stepKey="setDefaultTotalsSortOrder"/> </after> - <actionGroup ref="VerifyDiscountAmount" stepKey="verifyStorefront"> - <argument name="productUrl" value="$$simpleProduct.sku$$.html"/> - <argument name="quantity" value="1"/> + <actionGroup ref="AddSimpleProductToCart" stepKey="addProductToCart"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + + <actionGroup ref="VerifyDiscountAmount" stepKey="verifyDiscountAmount"> <argument name="expectedDiscount" value="-$100"/> </actionGroup> diff --git a/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml b/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml index 6b97c4e13caea..15f18c2ad2a6c 100644 --- a/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml +++ b/app/code/Magento/Sales/Test/Mftf/Data/SalesConfigData.xml @@ -31,10 +31,16 @@ <entity name="ShippingTotalsSortOrder" type="shipping"> <data key="value">27</data> </entity> - <entity name="DefaultCheckoutTotalsSortOrder" type="default_checkout_totals_sort_order"> - <requiredEntity type="checkoutTotalFlagZero">DefaultTotalFlagZero</requiredEntity> + + <entity name="DefaultTotalsSortOrder" type="checkout_totals_sort_order"> + <requiredEntity type="shipping">DefaultShippingTotalSortOrder</requiredEntity> + </entity> + + <entity name="DefaultShippingTotalSortOrder" type="shipping"> + <requiredEntity type="shipping_inherit_value">DefaultTotalFlagDisabled</requiredEntity> </entity> - <entity name="DefaultTotalFlagZero" type="checkoutTotalFlagZero"> + + <entity name="DefaultTotalFlagDisabled" type="shipping_inherit_value"> <data key="value">0</data> </entity> </entities> diff --git a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml b/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml index 2ec7577bbf867..98c9fdb043dd6 100644 --- a/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml +++ b/app/code/Magento/Sales/Test/Mftf/Metadata/sales_config-meta.xml @@ -26,57 +26,37 @@ <object key="fields" dataType="checkout_totals_sort_order"> <object key="subtotal" dataType="subtotal"> <field key="value">integer</field> - </object> - <object key="discount" dataType="discount"> - <field key="value">integer</field> - </object> - <object key="shipping" dataType="shipping"> - <field key="value">integer</field> - </object> - <object key="tax" dataType="tax"> - <field key="value">integer</field> - </object> - <object key="weee" dataType="weee"> - <field key="value">integer</field> - </object> - <object key="grand_total" dataType="grand_total"> - <field key="value">integer</field> - </object> - </object> - </object> - </object> - </operation> - <operation name="DefaultCheckoutTotalsSortOrder" dataType="default_checkout_totals_sort_order" type="create" auth="adminFormKey" url="/admin/system_config/save/section/sales/" method="POST" successRegex="/messages-message-success/"> - <object key="groups" dataType="default_checkout_totals_sort_order"> - <object key="totals_sort" dataType="default_checkout_totals_sort_order"> - <object key="fields" dataType="default_checkout_totals_sort_order"> - <object key="subtotal" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> + <object key="inherit" dataType="subtotal_inherit_value"> <field key="value">integer</field> </object> </object> - <object key="discount" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> + <object key="discount" dataType="discount"> + <field key="value">integer</field> + <object key="inherit" dataType="discount_inherit_value"> <field key="value">integer</field> </object> </object> - <object key="shipping" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> + <object key="shipping" dataType="shipping"> + <field key="value">integer</field> + <object key="inherit" dataType="shipping_inherit_value"> <field key="value">integer</field> </object> </object> - <object key="tax" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> + <object key="tax" dataType="tax"> + <field key="value">integer</field> + <object key="inherit" dataType="tax_inherit_value"> <field key="value">integer</field> </object> </object> - <object key="weee" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> + <object key="weee" dataType="weee"> + <field key="value">integer</field> + <object key="inherit" dataType="weee_inherit_value"> <field key="value">integer</field> </object> </object> - <object key="grand_total" dataType="default_checkout_totals_sort_order"> - <object key="inherit" dataType="checkoutTotalFlagZero"> + <object key="grand_total" dataType="grand_total"> + <field key="value">integer</field> + <object key="inherit" dataType="grand_total_inherit_value"> <field key="value">integer</field> </object> </object> diff --git a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml index 3176721baffda..35feabc8d9fbe 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/ActionGroup/StorefrontSalesRuleActionGroup.xml @@ -9,14 +9,8 @@ xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="VerifyDiscountAmount"> <arguments> - <argument name="productUrl" type="string"/> - <argument name="quantity" type="string"/> <argument name="expectedDiscount" type="string"/> </arguments> - <amOnPage url="{{productUrl}}" stepKey="goToProductPage"/> - <fillField selector="{{StorefrontProductActionSection.quantity}}" userInput="{{quantity}}" stepKey="fillQuantity"/> - <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addProductToCart"/> - <waitForPageLoad stepKey="waitForAddToCart"/> <amOnPage url="{{CheckoutCartPage.url}}" stepKey="goToCartPage"/> <waitForElementVisible selector="{{StorefrontCheckoutCartSummarySection.discountAmount}}" stepKey="waitForDiscountElement"/> <see selector="{{StorefrontCheckoutCartSummarySection.discountAmount}}" userInput="{{expectedDiscount}}" stepKey="seeDiscountTotal"/> From ae5eac3865660cba5f4b26ef96f2a6e5da3c9223 Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Thu, 29 Nov 2018 14:48:47 +0200 Subject: [PATCH 38/88] MAGETWO-88736: Issue with Newsletter subscriptions --- .../Test/Unit/Model/SubscriberTest.php | 6 ++- .../Newsletter/Model/SubscriberTest.php | 48 ++++++++++++++++++- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php b/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php index 9c543c831ded3..d8c770f02e8a7 100644 --- a/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php +++ b/app/code/Magento/Newsletter/Test/Unit/Model/SubscriberTest.php @@ -211,6 +211,7 @@ public function testSubscribeNotLoggedIn() public function testUpdateSubscription() { + $websiteId = 1; $storeId = 2; $customerId = 1; $customerDataMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) @@ -234,13 +235,16 @@ public function testUpdateSubscription() ->with($customerId) ->willReturn('account_confirmation_required'); $customerDataMock->expects($this->exactly(2))->method('getStoreId')->willReturn($storeId); + $customerDataMock->expects($this->exactly(2))->method('getWebsiteId')->willReturn(null); + $customerDataMock->expects($this->exactly(2))->method('setWebsiteId')->with($websiteId)->willReturnSelf(); $customerDataMock->expects($this->once())->method('getEmail')->willReturn('email'); $storeModel = $this->getMockBuilder(\Magento\Store\Model\Store::class) ->disableOriginalConstructor() - ->setMethods(['getId']) + ->setMethods(['getId', 'getWebsiteId']) ->getMock(); $this->storeManager->expects($this->any())->method('getStore')->willReturn($storeModel); + $storeModel->expects($this->exactly(2))->method('getWebsiteId')->willReturn($websiteId); $this->assertEquals($this->subscriber, $this->subscriber->updateSubscription($customerId)); } diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php index c6ba498319ff8..871657fa6e6d4 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php @@ -8,6 +8,11 @@ class SubscriberTest extends \PHPUnit\Framework\TestCase { + /** + * @var \Magento\TestFramework\ObjectManager + */ + private $objectManager; + /** * @var Subscriber */ @@ -15,7 +20,8 @@ class SubscriberTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->_model = $this->objectManager->create( \Magento\Newsletter\Model\Subscriber::class ); } @@ -27,7 +33,7 @@ protected function setUp() public function testEmailConfirmation() { $this->_model->subscribe('customer_confirm@example.com'); - $transportBuilder = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + $transportBuilder = $this->objectManager ->get(\Magento\TestFramework\Mail\Template\TransportBuilderMock::class); // confirmationCode 'ysayquyajua23iq29gxwu2eax2qb6gvy' is taken from fixture $this->assertContains( @@ -77,4 +83,42 @@ public function testUnsubscribeSubscribeByCustomerId() $this->assertSame($this->_model, $this->_model->subscribeCustomerById(1)); $this->assertEquals(Subscriber::STATUS_SUBSCRIBED, $this->_model->getSubscriberStatus()); } + + /** + * @magentoDataFixture Magento/Store/_files/second_store.php + */ + public function testSubscribeGuestRegisterCustomerWithSameEmailFromDifferentStore() + { + /** @var \Magento\Store\Model\Store $store */ + $store = $this->objectManager->create(\Magento\Store\Model\Store::class); + $defaultStoreId = $store->load('default', 'code')->getId(); + $secondStoreId = $store->load('fixture_second_store', 'code')->getId(); + + $email = 'test@example.com'; + + // Subscribing guest to a newsletter from default store + $this->_model->setStoreId($defaultStoreId) + ->setCustomerId(0) + ->setSubscriberEmail($email) + ->setSubscriberStatus(\Magento\Newsletter\Model\Subscriber::STATUS_SUBSCRIBED) + ->save(); + + // Registering customer with the same email from second store + $customer = $this->objectManager->create(\Magento\Customer\Model\Data\Customer::class, [ + 'data' => [ + \Magento\Customer\Model\Data\Customer::FIRSTNAME => 'John', + \Magento\Customer\Model\Data\Customer::LASTNAME => 'Doe', + \Magento\Customer\Model\Data\Customer::EMAIL => $email, + \Magento\Customer\Model\Data\Customer::STORE_ID => $secondStoreId, + ] + ]); + + /** @var \Magento\Customer\Api\AccountManagementInterface $accountManagement */ + $accountManagement = $this->objectManager->get(\Magento\Customer\Api\AccountManagementInterface::class); + $accountManagement->createAccount($customer); + + $subscribers = $this->_model->getCollection()->getItems(); + + $this->assertCount(1, $subscribers); + } } From addb913bc7b62fb0c0b58b1a5cf80118f0e041bd Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Thu, 29 Nov 2018 15:16:04 +0200 Subject: [PATCH 39/88] MAGETWO-95653: Product positions are incorrect after import --- .../Magento/Catalog/Model/Category/Product/PositionResolver.php | 2 ++ .../Test/Unit/Model/Category/Product/PositionResolverTest.php | 2 +- app/code/Magento/CatalogImportExport/Model/Import/Product.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php b/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php index 97941f2d23b9f..edaac39864c5a 100644 --- a/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php +++ b/app/code/Magento/Catalog/Model/Category/Product/PositionResolver.php @@ -52,6 +52,8 @@ public function getPositions(int $categoryId) $categoryId )->order( 'ccp.position ' . \Magento\Framework\DB\Select::SQL_ASC + )->order( + 'ccp.product_id ' . \Magento\Framework\DB\Select::SQL_DESC ); return array_flip($connection->fetchCol($select)); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php index 9545e5eb4b37d..a2424c7521e18 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Product/PositionResolverTest.php @@ -105,7 +105,7 @@ public function testGetPositions() $this->select->expects($this->once()) ->method('where') ->willReturnSelf(); - $this->select->expects($this->once()) + $this->select->expects($this->exactly(2)) ->method('order') ->willReturnSelf(); $this->select->expects($this->once()) diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 84fa13e6599d9..2f1d0764d01f2 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1372,7 +1372,7 @@ protected function _saveProductCategories(array $categoriesData) $delProductId[] = $productId; foreach (array_keys($categories) as $categoryId) { - $categoriesIn[] = ['product_id' => $productId, 'category_id' => $categoryId, 'position' => 1]; + $categoriesIn[] = ['product_id' => $productId, 'category_id' => $categoryId, 'position' => 0]; } } if (Import::BEHAVIOR_APPEND != $this->getBehavior()) { From df0909e3cce3690de6d81d91f731f2b27fb9620a Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Thu, 29 Nov 2018 06:36:24 -0800 Subject: [PATCH 40/88] MAGETWO-95738: Shared gift registry does not show the special price for a configurable product --- .../Block/Cart/Item/Renderer/Configurable.php | 8 ++++ .../Cart/Item/Renderer/ConfigurableTest.php | 48 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php b/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php index 4c7c5df736112..b128458665d73 100644 --- a/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Block/Cart/Item/Renderer/Configurable.php @@ -70,4 +70,12 @@ public function getIdentities() } return $identities; } + + /** + * @inheritdoc + */ + public function getProductPriceHtml(\Magento\Catalog\Model\Product $product) + { + return parent::getProductPriceHtml($this->getChildProduct()); + } } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php index f324494f5918a..cd722e39be2c9 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php @@ -30,6 +30,16 @@ class ConfigurableTest extends \PHPUnit\Framework\TestCase */ private $productConfigMock; + /** + * @var \Magento\Backend\Block\Template\Context|\PHPUnit_Framework_MockObject_MockObject + */ + private $contextMock; + + /** + * @var \Magento\Framework\View\Layout|PHPUnit_Framework_MockObject_MockObject + */ + private $layoutMock; + /** * @var Renderer */ @@ -39,6 +49,10 @@ protected function setUp() { parent::setUp(); $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->contextMock = $this->createPartialMock(\Magento\Backend\Block\Template\Context::class,['getLayout']); + $this->layoutMock = $this->createPartialMock(\Magento\Framework\View\Layout::class, ['getBlock']); + $this->contextMock->expects($this->once())->method('getLayout')->willReturn($this->layoutMock); + $this->configManager = $this->createMock(\Magento\Framework\View\ConfigInterface::class); $this->imageHelper = $this->createPartialMock( \Magento\Catalog\Helper\Image::class, @@ -53,6 +67,7 @@ protected function setUp() 'imageHelper' => $this->imageHelper, 'scopeConfig' => $this->scopeConfig, 'productConfig' => $this->productConfigMock, + 'context' => $this->contextMock, ] ); } @@ -75,4 +90,37 @@ public function testGetIdentities() $this->renderer->setItem($item); $this->assertEquals(array_merge($productTags, $productTags), $this->renderer->getIdentities()); } + + public function testGetProductPriceHtml() + { + $priceHtml = 'some price html'; + $productMock = $this->createMock(\Magento\Catalog\Model\Product::class); + + $item = $this->createMock(\Magento\Quote\Model\Quote\Item::class); + $item->expects($this->atLeastOnce())->method('getProduct')->willReturn($productMock); + + $priceRender = $this->getMockBuilder(\Magento\Framework\Pricing\Render::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->layoutMock->expects($this->once()) + ->method('getBlock') + ->with('product.price.render.default') + ->willReturn($priceRender); + + $priceRender->expects($this->once()) + ->method('render') + ->with( + \Magento\Catalog\Pricing\Price\ConfiguredPriceInterface::CONFIGURED_PRICE_CODE, + $productMock, + [ + 'include_container' => true, + 'display_minimal_price' => true, + 'zone' => \Magento\Framework\Pricing\Render::ZONE_ITEM_LIST, + ] + )->willReturn($priceHtml); + + $this->renderer->setItem($item); + $this->assertEquals($priceHtml, $this->renderer->getProductPriceHtml($productMock)); + } } From f9ef725c24e3c227600dfb49126f04f9ea8e4c48 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Thu, 29 Nov 2018 07:02:24 -0800 Subject: [PATCH 41/88] MAGETWO-95738: Shared gift registry does not show the special price for a configurable product --- .../Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php index cd722e39be2c9..51a1dc7d0ea3f 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php @@ -8,6 +8,9 @@ use Magento\Catalog\Model\Config\Source\Product\Thumbnail as ThumbnailSource; use Magento\ConfigurableProduct\Block\Cart\Item\Renderer\Configurable as Renderer; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class ConfigurableTest extends \PHPUnit\Framework\TestCase { /** @@ -49,7 +52,7 @@ protected function setUp() { parent::setUp(); $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->contextMock = $this->createPartialMock(\Magento\Backend\Block\Template\Context::class,['getLayout']); + $this->contextMock = $this->createPartialMock(\Magento\Backend\Block\Template\Context::class, ['getLayout']); $this->layoutMock = $this->createPartialMock(\Magento\Framework\View\Layout::class, ['getBlock']); $this->contextMock->expects($this->once())->method('getLayout')->willReturn($this->layoutMock); From 50401f9f5f397822b2e7d1089c0f275fa28ebe57 Mon Sep 17 00:00:00 2001 From: Viktor Petryk <victor.petryk@transoftgroup.com> Date: Thu, 29 Nov 2018 18:22:01 +0200 Subject: [PATCH 42/88] MAGETWO-88736: Issue with Newsletter subscriptions --- .../Newsletter/Model/SubscriberTest.php | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php index 871657fa6e6d4..6c7aa204fded2 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Model/SubscriberTest.php @@ -104,21 +104,26 @@ public function testSubscribeGuestRegisterCustomerWithSameEmailFromDifferentStor ->save(); // Registering customer with the same email from second store - $customer = $this->objectManager->create(\Magento\Customer\Model\Data\Customer::class, [ - 'data' => [ - \Magento\Customer\Model\Data\Customer::FIRSTNAME => 'John', - \Magento\Customer\Model\Data\Customer::LASTNAME => 'Doe', - \Magento\Customer\Model\Data\Customer::EMAIL => $email, - \Magento\Customer\Model\Data\Customer::STORE_ID => $secondStoreId, + $customer = $this->objectManager->create( + \Magento\Customer\Model\Data\Customer::class, + [ + 'data' => [ + \Magento\Customer\Model\Data\Customer::FIRSTNAME => 'John', + \Magento\Customer\Model\Data\Customer::LASTNAME => 'Doe', + \Magento\Customer\Model\Data\Customer::EMAIL => $email, + \Magento\Customer\Model\Data\Customer::STORE_ID => $secondStoreId, + ] ] - ]); + ); /** @var \Magento\Customer\Api\AccountManagementInterface $accountManagement */ $accountManagement = $this->objectManager->get(\Magento\Customer\Api\AccountManagementInterface::class); - $accountManagement->createAccount($customer); + $customer = $accountManagement->createAccount($customer); - $subscribers = $this->_model->getCollection()->getItems(); + /** @var \Magento\Newsletter\Model\ResourceModel\Subscriber\Collection $subscribers */ + $subscribers = $this->_model->getCollection()->addFieldToFilter('subscriber_email', $email); - $this->assertCount(1, $subscribers); + $this->assertCount(1, $subscribers->getItems()); + $this->assertEquals($subscribers->getFirstItem()->getCustomerId(), $customer->getId()); } } From fda295f880075c896e599617a37e4912f4e040ef Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Fri, 30 Nov 2018 01:26:54 -0800 Subject: [PATCH 43/88] MAGETWO-95738: Shared gift registry does not show the special price for a configurable product --- .../Block/Cart/Item/Renderer/ConfigurableTest.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php index 51a1dc7d0ea3f..698a7ac9f2693 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Block/Cart/Item/Renderer/ConfigurableTest.php @@ -94,6 +94,11 @@ public function testGetIdentities() $this->assertEquals(array_merge($productTags, $productTags), $this->renderer->getIdentities()); } + /** + * Product price renderer test. + * + * @return void + */ public function testGetProductPriceHtml() { $priceHtml = 'some price html'; @@ -102,16 +107,16 @@ public function testGetProductPriceHtml() $item = $this->createMock(\Magento\Quote\Model\Quote\Item::class); $item->expects($this->atLeastOnce())->method('getProduct')->willReturn($productMock); - $priceRender = $this->getMockBuilder(\Magento\Framework\Pricing\Render::class) + $priceRenderMock = $this->getMockBuilder(\Magento\Framework\Pricing\Render::class) ->disableOriginalConstructor() ->getMock(); $this->layoutMock->expects($this->once()) ->method('getBlock') ->with('product.price.render.default') - ->willReturn($priceRender); + ->willReturn($priceRenderMock); - $priceRender->expects($this->once()) + $priceRenderMock->expects($this->once()) ->method('render') ->with( \Magento\Catalog\Pricing\Price\ConfiguredPriceInterface::CONFIGURED_PRICE_CODE, From 99e3789ed5d83d372bc5770b749b197d26fb7262 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Fri, 30 Nov 2018 11:30:28 +0200 Subject: [PATCH 44/88] MAGETWO-95218: Order fails on review step with zero grand total --- .../Controller/Express/AbstractExpress.php | 18 +++++++-- .../Magento/Paypal/Controller/ExpressTest.php | 38 +++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php b/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php index 571d73d07b68e..95804ebe45d8c 100644 --- a/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php +++ b/app/code/Magento/Paypal/Controller/Express/AbstractExpress.php @@ -137,6 +137,14 @@ protected function _initCheckout() $this->getResponse()->setStatusHeader(403, '1.1', 'Forbidden'); throw new \Magento\Framework\Exception\LocalizedException(__('We can\'t initialize Express Checkout.')); } + if (!(float)$quote->getGrandTotal()) { + throw new \Magento\Framework\Exception\LocalizedException( + __( + 'PayPal can\'t process orders with a zero balance due. ' + . 'To finish your purchase, please go through the standard checkout process.' + ) + ); + } if (!isset($this->_checkoutTypes[$this->_checkoutType])) { $parameters = [ 'params' => [ @@ -151,6 +159,8 @@ protected function _initCheckout() } /** + * Get proper checkout token. + * * Search for proper checkout token in request or session or (un)set specified one * Combined getter/setter * @@ -221,8 +231,7 @@ protected function _getQuote() } /** - * Returns before_auth_url redirect parameter for customer session - * @return null + * @inheritdoc */ public function getCustomerBeforeAuthUrl() { @@ -230,8 +239,7 @@ public function getCustomerBeforeAuthUrl() } /** - * Returns a list of action flags [flag_key] => boolean - * @return array + * @inheritdoc */ public function getActionFlagList() { @@ -240,6 +248,7 @@ public function getActionFlagList() /** * Returns login url parameter for redirect + * * @return string */ public function getLoginUrl() @@ -249,6 +258,7 @@ public function getLoginUrl() /** * Returns action name which requires redirect + * * @return string */ public function getRedirectActionName() diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php index 95e3abbfe6ff1..d10befc3a811c 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Controller/ExpressTest.php @@ -226,4 +226,42 @@ public function testReturnAction() $this->_objectManager->removeSharedInstance(ApiFactory::class); $this->_objectManager->removeSharedInstance(PaypalSession::class); } + + /** + * @magentoConfigFixture current_store carriers/freeshipping/active 1 + * @magentoDataFixture Magento/Sales/_files/quote.php + * @magentoDataFixture Magento/Paypal/_files/quote_payment.php + * @return void + */ + public function testPlaceOrderZeroGrandTotal() + { + /** @var Quote $quote */ + $quote = $this->_objectManager->create(Quote::class); + $quote->load('test01', 'reserved_order_id'); + $quote->getShippingAddress()->setShippingMethod('freeshipping'); + $quote->getShippingAddress()->setCollectShippingRates(true); + /** @var \Magento\Quote\Model\Quote\Item[] $items */ + $items = $quote->getItemsCollection()->getItems(); + $quoteItem = reset($items); + /** @var \Magento\Quote\Model\Quote\Item\Updater $quoteItemUpdater */ + $quoteItemUpdater = $this->_objectManager->get(\Magento\Quote\Model\Quote\Item\Updater::class); + $quoteItemUpdater->update($quoteItem, ['qty' => 1, 'custom_price' => 0]); + $quote->setTotalsCollectedFlag(false)->collectTotals()->save(); + + $this->_objectManager->get(Session::class)->setQuoteId($quote->getId()); + + $this->dispatch('paypal/express/placeOrder'); + $this->assertSessionMessages( + $this->equalTo( + [ + htmlspecialchars( + (string)__('PayPal can\'t process orders with a zero balance due. ' + . 'To finish your purchase, please go through the standard checkout process.'), + ENT_QUOTES + ) + ] + ), + \Magento\Framework\Message\MessageInterface::TYPE_ERROR + ); + } } From 45c4b6c639fd89780b84dc5a0e11d34c48734c46 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Mon, 3 Dec 2018 10:16:50 +0200 Subject: [PATCH 45/88] MAGETWO-90930: Problems with operator more/less in the "catalog Products List" widget - Fix Builder sql - Added Unit test - Added automated test --- .../Section/AdminCategoryContentSection.xml | 15 ++ .../AdminCategoryDisplaySettingsSection.xml | 15 ++ .../AdminCreateBlockWithWidgetActionGroup.xml | 45 ++++++ ...nCatalogProductListWidgetOperatorsTest.xml | 144 ++++++++++++++++++ .../NavigateToCMSPagesActionGroup.xml | 22 +++ .../Cms/Test/Mftf/Data/CmsBlockData.xml | 17 +++ .../Cms/Test/Mftf/Metadata/cms_block-meta.xml | 23 +++ .../Test/Mftf/Page/AdminCmsBlockEditPage.xml | 14 ++ .../Test/Mftf/Page/AdminCmsBlockGridPage.xml | 13 ++ .../Section/AdminCmsBlockContentSection.xml | 15 ++ .../Rule/Model/Condition/Sql/Builder.php | 4 + .../Unit/Model/Condition/Sql/BuilderTest.php | 65 ++++++++ .../Section/AdminDataGridTableSection.xml | 2 + .../Mftf/Section/AdminNewWidgetSection.xml | 4 + .../Mftf/Section/StorefrontWidgetsSection.xml | 1 + 15 files changed, 399 insertions(+) create mode 100644 app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml create mode 100644 app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml create mode 100644 app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml create mode 100644 app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml create mode 100644 app/code/Magento/Cms/Test/Mftf/ActionGroup/NavigateToCMSPagesActionGroup.xml create mode 100644 app/code/Magento/Cms/Test/Mftf/Data/CmsBlockData.xml create mode 100644 app/code/Magento/Cms/Test/Mftf/Metadata/cms_block-meta.xml create mode 100644 app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockEditPage.xml create mode 100644 app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockGridPage.xml create mode 100644 app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml new file mode 100644 index 0000000000000..faa320cd114de --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryContentSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCategoryContentSection"> + <element name="sectionHeader" type="button" selector="div[data-index='content']" timeout="30"/> + <element name="addCMSBlock" type="select" selector="[name='landing_page']"/> + </section> +</sections> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml new file mode 100644 index 0000000000000..d545feca3e711 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminCategoryDisplaySettingsSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCategoryDisplaySettingsSection"> + <element name="settingsHeader" type="button" selector="[data-index='display_settings'] strong.admin__collapsible-title" timeout="30"/> + <element name="displayMode" type="button" selector="[name='display_mode']"/> + </section> +</sections> diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml b/app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml new file mode 100644 index 0000000000000..3631e56fcdcf0 --- /dev/null +++ b/app/code/Magento/CatalogWidget/Test/Mftf/ActionGroup/AdminCreateBlockWithWidgetActionGroup.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminCreateCmsBlockWithCatalogProductListWidget"> + <arguments> + <argument name="conditionAttribute" type="string"/> + <argument name="conditionOperator" type="string"/> + <argument name="conditionValue" type="string"/> + </arguments> + <fillField selector="{{AdminCmsBlockContentSection.content}}" userInput="" stepKey="makeContentFieldEmpty"/> + + <click selector="{{AdminCmsBlockContentSection.insertWidgetButton}}" stepKey="clickInsertWidgetButton"/> + <waitForElementVisible selector="{{AdminNewWidgetSection.widgetTypeDropDown}}" time="10" stepKey="waitForInsertWidgetFrame"/> + + <selectOption selector="{{AdminNewWidgetSection.widgetTypeDropDown}}" userInput="Catalog Products List" stepKey="selectCatalogProductListOption"/> + <waitForElementVisible selector="{{AdminNewWidgetSection.addNewCondition}}" stepKey="waitForConditionsElementBecomeAvailable"/> + + <click selector="{{AdminNewWidgetSection.addNewCondition}}" stepKey="clickToAddCondition"/> + <waitForElementVisible selector="{{AdminNewWidgetSection.selectCondition}}" stepKey="waitForSelectBoxOpened"/> + + <selectOption selector="{{AdminNewWidgetSection.selectCondition}}" userInput="{{conditionAttribute}}" stepKey="selectConditionsSelectBox"/> + <waitForElementVisible selector="{{AdminNewWidgetSection.ruleParameter}}" stepKey="seeConditionsAdded"/> + + <click selector="{{AdminNewWidgetSection.conditionOperator}}" stepKey="clickToConditionIs"/> + <selectOption selector="{{AdminNewWidgetSection.conditionOperatorSelect('1')}}" userInput="{{conditionOperator}}" stepKey="selectOperator"/> + + <click selector="{{AdminNewWidgetSection.ruleParameter}}" stepKey="clickAddConditionItem"/> + <waitForElementVisible selector="{{AdminNewWidgetSection.setRuleParameter}}" stepKey="waitForConditionFieldOpened"/> + + <fillField selector="{{AdminNewWidgetSection.setRuleParameter}}" userInput="{{conditionValue}}" stepKey="setConditionValue"/> + <click selector="{{AdminNewWidgetSection.insertWidget}}" stepKey="clickInsertWidget"/> + + <waitForElementVisible selector="{{AdminMainActionsSection.save}}" stepKey="waitForInsertWidgetSaved"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveButton"/> + <see userInput="You saved the block." stepKey="seeSavedBlockMsgOnForm"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingOrderFilters"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml b/app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml new file mode 100644 index 0000000000000..6fe2e46fd8090 --- /dev/null +++ b/app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml @@ -0,0 +1,144 @@ +<?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="AdminCatalogProductListWidgetOperatorsTest"> + <annotations> + <features value="CatalogWidget"/> + <stories value="MAGETWO-90930: Problems with operator more/less in the 'catalog Products List' widget"/> + <title value="Checking operator more/less in the 'catalog Products List' widget"/> + <description value="Check 'less than', 'equals or greater than', 'equals or less than' operators"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-96479"/> + <group value="catalogWidget"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="createSimpleCategory"/> + <createData entity="SimpleProduct" stepKey="createFirstProduct"> + <requiredEntity createDataKey="createSimpleCategory"/> + <field key="price">10</field> + </createData> + <createData entity="SimpleProduct" stepKey="createSecondProduct"> + <requiredEntity createDataKey="createSimpleCategory"/> + <field key="price">50</field> + </createData> + <createData entity="SimpleProduct" stepKey="createThirdProduct"> + <requiredEntity createDataKey="createSimpleCategory"/> + <field key="price">100</field> + </createData> + <createData entity="DefaultCmsBlock" stepKey="createPreReqBlock"/> + <!--User log in on back-end as admin--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createPreReqBlock" stepKey="deletePreReqBlock" /> + <deleteData createDataKey="createSimpleCategory" stepKey="deleteSimpleCategory"/> + <deleteData createDataKey="createFirstProduct" stepKey="deleteFirstProduct"/> + <deleteData createDataKey="createSecondProduct" stepKey="deleteSecondProduct"/> + <deleteData createDataKey="createThirdProduct" stepKey="deleteThirdProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open block with widget--> + <actionGroup ref="NavigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage1"> + <argument name="cmsBlock" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateCmsBlockWithCatalogProductListWidget" stepKey="adminCreateBlockWithWidget"> + <argument name="conditionAttribute" value="Price"/> + <argument name="conditionOperator" value="greater than"/> + <argument name="conditionValue" value="20"/> + </actionGroup> + + <!--Go to Catalog > Categories (choose category where created products)--> + <amOnPage url="{{AdminCategoryPage.url}}" stepKey="onCategoryIndexPage"/> + <click selector="{{AdminCategorySidebarTreeSection.expandAll}}" stepKey="clickExpandAll"/> + <waitForElementVisible selector="{{AdminCategorySidebarTreeSection.categoryInTree(SimpleSubCategory.name)}}" stepKey="waitForCategoryVisible"/> + <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(SimpleSubCategory.name)}}" stepKey="clickCategoryLink"/> + + <!--Categories > Content > Add CMS Block: name saved block--> + <waitForElementVisible selector="{{AdminCategoryContentSection.sectionHeader}}" stepKey="waitForContentSection"/> + <conditionalClick selector="{{AdminCategoryContentSection.sectionHeader}}" dependentSelector="{{AdminCategoryContentSection.uploadButton}}" visible="false" stepKey="openContentSection"/> + + <selectOption selector="{{AdminCategoryContentSection.addCMSBlock}}" userInput="{{DefaultCmsBlock.title}}" stepKey="selectSavedBlock"/> + + <!--Display Settings > Display Mode: Static block only--> + <waitForElementVisible selector="{{AdminCategoryDisplaySettingsSection.settingsHeader}}" stepKey="waitForDisplaySettingsSection"/> + <conditionalClick selector="{{AdminCategoryDisplaySettingsSection.settingsHeader}}" dependentSelector="{{AdminCategoryDisplaySettingsSection.displayMode}}" visible="false" stepKey="openDisplaySettingsSection"/> + <selectOption userInput="Static block only" selector="{{AdminCategoryDisplaySettingsSection.displayMode}}" stepKey="selectStaticBlockOnlyOption"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="saveCategoryWithProducts"/> + <see userInput="You saved the category." stepKey="seeSuccessMessage"/> + + <!--Go to Storefront > category--> + <amOnPage url="{{StorefrontCategoryPage.url($$createSimpleCategory.name$$)}}" stepKey="goToStorefrontCategoryPage1"/> + + <!--Check operators Greater than--> + <dontSeeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('10')}}" stepKey="dontSeeElementByPrice10"/> + <seeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('50')}}" stepKey="seeElementByPrice50"/> + <seeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('100')}}" stepKey="seeElementByPrice100"/> + + <!--Open block with widget.--> + <actionGroup ref="NavigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage2"> + <argument name="cmsBlock" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateCmsBlockWithCatalogProductListWidget" stepKey="adminCreateBlockWithWidgetLessThan"> + <argument name="conditionAttribute" value="Price"/> + <argument name="conditionOperator" value="less than"/> + <argument name="conditionValue" value="20"/> + </actionGroup> + + <!--Go to Storefront > category--> + <amOnPage url="{{StorefrontCategoryPage.url($$createSimpleCategory.name$$)}}" stepKey="goToStorefrontCategoryPage2"/> + + <!--Check operators Greater than--> + <seeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('10')}}" stepKey="seeElementByPrice10"/> + <dontSeeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('50')}}" stepKey="dontSeeElementByPrice50"/> + <dontSeeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('100')}}" stepKey="dontSeeElementByPrice100"/> + + <!--Open block with widget--> + <actionGroup ref="NavigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage3"> + <argument name="cmsBlock" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateCmsBlockWithCatalogProductListWidget" stepKey="adminCreateBlockWithWidgetEqualsOrGreaterThan"> + <argument name="conditionAttribute" value="Price"/> + <argument name="conditionOperator" value="equals or greater than"/> + <argument name="conditionValue" value="50"/> + </actionGroup> + + <!--Go to Storefront > category--> + <amOnPage url="{{StorefrontCategoryPage.url($$createSimpleCategory.name$$)}}" stepKey="goToStorefrontCategoryPage3"/> + + <!--Check operators Greater than--> + <dontSeeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('10')}}" stepKey="dontSeeElementByPrice10a"/> + <seeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('50')}}" stepKey="seeElementByPrice50a"/> + <seeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('100')}}" stepKey="seeElementByPrice100a"/> + + <!--Open block with widget--> + <actionGroup ref="NavigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage4"> + <argument name="cmsBlock" value="$$createPreReqBlock$$"/> + </actionGroup> + + <actionGroup ref="AdminCreateCmsBlockWithCatalogProductListWidget" stepKey="adminCreateBlockWithWidgetEqualsOrLessThan"> + <argument name="conditionAttribute" value="Price"/> + <argument name="conditionOperator" value="equals or less than"/> + <argument name="conditionValue" value="50"/> + </actionGroup> + + <!--Go to Storefront > category--> + <amOnPage url="{{StorefrontCategoryPage.url($$createSimpleCategory.name$$)}}" stepKey="goToStorefrontCategoryPage4"/> + + <!--Check operators Greater than--> + <seeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('10')}}" stepKey="seeElementByPrice10b"/> + <seeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('50')}}" stepKey="seeElementByPrice50b"/> + <dontSeeElement selector="{{StorefrontWidgetsSection.checkElementStorefrontByPrice('100')}}" stepKey="dontSeeElementByPrice100b"/> + </test> +</tests> diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/NavigateToCMSPagesActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/NavigateToCMSPagesActionGroup.xml new file mode 100644 index 0000000000000..6a2012b551407 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/NavigateToCMSPagesActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="NavigateToCreatedCMSBlockPage"> + <arguments> + <argument name="cmsBlock"/> + </arguments> + <amOnPage url="{{AdminCmsBlockGridPage.url}}" stepKey="navigateToCMSBlocksGrid"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clickToResetFilters"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="clickOnFilters"/> + <fillField userInput="{{cmsBlock.identifier}}" selector="{{AdminDataGridHeaderSection.filterFieldInput('identifier')}}" stepKey="fillFilterAttributeCodeField"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFiltersButton"/> + <click selector="{{AdminDataGridTableSection.rowActionSelect}}" stepKey="clickSelectCreatedCMSBlock" /> + <click selector="{{AdminDataGridTableSection.rowEditAction}}" stepKey="navigateToCreatedCMSBlock" /> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Cms/Test/Mftf/Data/CmsBlockData.xml b/app/code/Magento/Cms/Test/Mftf/Data/CmsBlockData.xml new file mode 100644 index 0000000000000..c8f71253dc6bd --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Data/CmsBlockData.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="DefaultCmsBlock" type="cms_block"> + <data key="title">Default Block</data> + <data key="identifier" unique="suffix" >block</data> + <data key="content">Here is a block test. Yeah!</data> + <data key="active">true</data> + </entity> +</entities> diff --git a/app/code/Magento/Cms/Test/Mftf/Metadata/cms_block-meta.xml b/app/code/Magento/Cms/Test/Mftf/Metadata/cms_block-meta.xml new file mode 100644 index 0000000000000..bab2be6a36155 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Metadata/cms_block-meta.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateCmsBlock" dataType="cms_block" type="create" auth="adminOauth" url="/V1/cmsBlock" method="POST"> + <contentType>application/json</contentType> + <object key="block" dataType="cms_block"> + <field key="title">string</field> + <field key="identifier">string</field> + <field key="content">string</field> + <field key="active">true</field> + </object> + </operation> + + <operation name="DeleteCmsBlock" dataType="cms_block" type="delete" auth="adminOauth" url="/V1/cmsBlock/{id}" method="DELETE"> + <contentType>application/json</contentType> + </operation> +</operations> diff --git a/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockEditPage.xml b/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockEditPage.xml new file mode 100644 index 0000000000000..a2e16b8f279df --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockEditPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminCmsBlockEditPage" url="/cms/block/edit/id/{{var1}}" area="admin" module="Magento_Cms" parameterized="true"> + <section name="AdminCmsBlockContentSection" /> + </page> +</pages> diff --git a/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockGridPage.xml b/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockGridPage.xml new file mode 100644 index 0000000000000..2cabe182714dc --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockGridPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="AdminCmsBlockGridPage" url="/cms/block/" area="admin" module="Magento_Cms"> + </page> +</pages> diff --git a/app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml b/app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml new file mode 100644 index 0000000000000..9614f13f9e3d3 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminCmsBlockContentSection"> + <element name="content" type="textarea" selector="#cms_block_form_content"/> + <element name="insertWidgetButton" type="button" selector=".scalable.action-add-widget.plugin"/> + </section> +</sections> diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index e2118445b6de7..51d79363cecfe 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -32,9 +32,13 @@ class Builder '==' => ':field = ?', '!=' => ':field <> ?', '>=' => ':field >= ?', + '>=' => ':field >= ?', '>' => ':field > ?', + '>' => ':field > ?', '<=' => ':field <= ?', + '<=' => ':field <= ?', '<' => ':field < ?', + '<' => ':field < ?', '{}' => ':field IN (?)', '!{}' => ':field NOT IN (?)', '()' => ':field IN (?)', diff --git a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php index 0a2767a94668a..7be94bf690e8b 100644 --- a/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php +++ b/app/code/Magento/Rule/Test/Unit/Model/Condition/Sql/BuilderTest.php @@ -72,4 +72,69 @@ public function testAttachConditionToCollection() $this->_builder->attachConditionToCollection($collection, $combine); } + + /** + * Test for attach condition to collection with operator in html format. + * + * @covers \Magento\Rule\Model\Condition\Sql\Builder::attachConditionToCollection() + * @return void + */ + public function testAttachConditionAsHtmlToCollection() + { + $abstractCondition = $this->getMockForAbstractClass( + \Magento\Rule\Model\Condition\AbstractCondition::class, + [], + '', + false, + false, + true, + ['getOperatorForValidate', 'getMappedSqlField', 'getAttribute', 'getBindArgumentValue'] + ); + + $abstractCondition->expects($this->once())->method('getMappedSqlField')->will($this->returnValue('argument')); + $abstractCondition->expects($this->once())->method('getOperatorForValidate')->will($this->returnValue('>')); + $abstractCondition->expects($this->at(1))->method('getAttribute')->will($this->returnValue('attribute')); + $abstractCondition->expects($this->at(2))->method('getAttribute')->will($this->returnValue('attribute')); + $abstractCondition->expects($this->once())->method('getBindArgumentValue')->will($this->returnValue(10)); + + $conditions = [$abstractCondition]; + $collection = $this->createPartialMock( + \Magento\Eav\Model\Entity\Collection\AbstractCollection::class, + [ + 'getResource', + 'getSelect', + ] + ); + $combine = $this->createPartialMock( + \Magento\Rule\Model\Condition\Combine::class, + [ + 'getConditions', + 'getValue', + 'getAggregator', + ] + ); + + $resource = $this->createPartialMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, ['getConnection']); + $select = $this->createPartialMock(\Magento\Framework\DB\Select::class, ['where']); + $select->expects($this->never())->method('where'); + + $connection = $this->getMockForAbstractClass( + \Magento\Framework\DB\Adapter\AdapterInterface::class, + ['quoteInto'], + '', + false + ); + + $connection->expects($this->once())->method('quoteInto')->with(' > ?', 10)->will($this->returnValue(' > 10')); + $collection->expects($this->once())->method('getResource')->will($this->returnValue($resource)); + $resource->expects($this->once())->method('getConnection')->will($this->returnValue($connection)); + $combine->expects($this->once())->method('getValue')->willReturn('attribute'); + $combine->expects($this->once())->method('getAggregator')->willReturn(' AND '); + $combine->expects($this->at(0))->method('getConditions')->will($this->returnValue($conditions)); + $combine->expects($this->at(1))->method('getConditions')->will($this->returnValue($conditions)); + $combine->expects($this->at(2))->method('getConditions')->will($this->returnValue($conditions)); + $combine->expects($this->at(3))->method('getConditions')->will($this->returnValue($conditions)); + + $this->_builder->attachConditionToCollection($collection, $combine); + } } diff --git a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml index ea0f7e64a8448..f5f8dedeefc91 100644 --- a/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml +++ b/app/code/Magento/Ui/Test/Mftf/Section/AdminDataGridTableSection.xml @@ -18,5 +18,7 @@ <!--Specific cell e.g. {{Section.gridCell('1', 'Name')}}--> <element name="gridCell" type="text" selector="//tr[{{row}}]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> + <element name="rowActionSelect" type="button" selector="[data-role='grid'] tbody tr .action-select-wrap"/> + <element name="rowEditAction" type="button" selector="[data-role='grid'] tbody tr .action-select-wrap._active [data-action='item-edit']" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml index b96d3865a6661..adf234baede72 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/AdminNewWidgetSection.xml @@ -27,5 +27,9 @@ <element name="selectAll" type="checkbox" selector=".admin__control-checkbox"/> <element name="sortById" type="button" selector="th.data-grid-th._sortable.not-sort.col-entity_id"/> <element name="sortByIdAscend" type="button" selector="th.data-grid-th._sortable._ascend.col-entity_id"/> + <element name="insertWidget" type="button" selector="#insert_button" timeout="30"/> + <element name="widgetTypeDropDown" type="select" selector="#select_widget_type"/> + <element name="conditionOperator" type="text" selector="//*[@id='conditions__1--1__attribute']/following-sibling::span[1]"/> + <element name="conditionOperatorSelect" type="select" selector="#conditions__1--{{arg1}}__operator" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Widget/Test/Mftf/Section/StorefrontWidgetsSection.xml b/app/code/Magento/Widget/Test/Mftf/Section/StorefrontWidgetsSection.xml index 23908626389f9..9d1944cc126b8 100644 --- a/app/code/Magento/Widget/Test/Mftf/Section/StorefrontWidgetsSection.xml +++ b/app/code/Magento/Widget/Test/Mftf/Section/StorefrontWidgetsSection.xml @@ -11,5 +11,6 @@ <section name="StorefrontWidgetsSection"> <element name="widgetProductsGrid" type="block" selector=".block.widget.block-products-list.grid"/> <element name="widgetProductName" type="text" selector=".product-item-name"/> + <element name="checkElementStorefrontByPrice" type="text" selector="//*[@class='product-items widget-product-grid']//*[contains(text(),'${{arg2}}.00')]" parameterized="true"/> </section> </sections> From 7fb8f0421c9eaca29b3ef9f6a2554c3abb395377 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Mon, 3 Dec 2018 10:46:12 +0200 Subject: [PATCH 46/88] MAGETWO-90930: Problems with operator more/less in the "catalog Products List" widget - Automated test fix --- .../Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml b/app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml index 6fe2e46fd8090..a78cb7d06699c 100644 --- a/app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml +++ b/app/code/Magento/CatalogWidget/Test/Mftf/Test/AdminCatalogProductListWidgetOperatorsTest.xml @@ -65,7 +65,7 @@ <!--Categories > Content > Add CMS Block: name saved block--> <waitForElementVisible selector="{{AdminCategoryContentSection.sectionHeader}}" stepKey="waitForContentSection"/> - <conditionalClick selector="{{AdminCategoryContentSection.sectionHeader}}" dependentSelector="{{AdminCategoryContentSection.uploadButton}}" visible="false" stepKey="openContentSection"/> + <conditionalClick selector="{{AdminCategoryContentSection.sectionHeader}}" dependentSelector="{{AdminCategoryContentSection.addCMSBlock}}" visible="false" stepKey="openContentSection"/> <selectOption selector="{{AdminCategoryContentSection.addCMSBlock}}" userInput="{{DefaultCmsBlock.title}}" stepKey="selectSavedBlock"/> From ca7ea2e866db840daed5336d08e5e70281960449 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Mon, 3 Dec 2018 12:24:11 +0200 Subject: [PATCH 47/88] MAGETWO-90930: Problems with operator more/less in the "catalog Products List" widget - Automated test fix --- .../Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml index 68c432a136ac9..c031578e2a208 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminCategoryEditPage.xml @@ -16,5 +16,7 @@ <section name="AdminCategoryBasicFieldSection"/> <section name="AdminCategorySEOSection"/> <section name="AdminCategoryModalSection"/> + <section name="AdminCategoryContentSection"/> + <section name="AdminCategoryDisplaySettingsSection"/> </page> </pages> From ec36dd9fef7492f1a112c453ab700491029bdbf5 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Mon, 3 Dec 2018 13:46:25 +0200 Subject: [PATCH 48/88] MAGETWO-96587: Investigation an issue that an exception appears after an order has been payed --- .../Controller/Paypal/PlaceOrder.php | 9 +- .../Model/Paypal/Helper/OrderPlace.php | 30 ++- .../Model/Paypal/OrderCancellationService.php | 76 ++++++++ .../Braintree/Plugin/OrderCancellation.php | 79 ++++++++ .../Unit/Controller/Paypal/PlaceOrderTest.php | 142 +++++++------- .../Model/Paypal/Helper/OrderPlaceTest.php | 135 ++++++++------ app/code/Magento/Braintree/etc/di.xml | 4 + app/code/Magento/Braintree/i18n/en_US.csv | 1 + .../Controller/Paypal/PlaceOrderTest.php | 173 ++++++++++++++++++ .../Braintree/Fixtures/paypal_quote.php | 29 +++ .../Fixtures/paypal_quote_rollback.php | 9 + .../App/Action/HttpPostActionInterface.php | 19 ++ 12 files changed, 570 insertions(+), 136 deletions(-) create mode 100644 app/code/Magento/Braintree/Model/Paypal/OrderCancellationService.php create mode 100644 app/code/Magento/Braintree/Plugin/OrderCancellation.php create mode 100644 dev/tests/integration/testsuite/Magento/Braintree/Controller/Paypal/PlaceOrderTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote.php create mode 100644 dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote_rollback.php create mode 100644 lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php diff --git a/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php b/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php index 1acd16708ff42..418cb93900610 100644 --- a/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php +++ b/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php @@ -9,6 +9,7 @@ use Magento\Braintree\Model\Paypal\Helper; use Magento\Checkout\Model\Session; use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\ObjectManager; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\LocalizedException; @@ -17,7 +18,7 @@ /** * Class PlaceOrder */ -class PlaceOrder extends AbstractAction +class PlaceOrder extends AbstractAction implements HttpPostActionInterface { /** * @var Helper\OrderPlace @@ -54,6 +55,7 @@ public function __construct( /** * @inheritdoc + * * @throws LocalizedException */ public function execute() @@ -71,7 +73,10 @@ public function execute() return $resultRedirect->setPath('checkout/onepage/success', ['_secure' => true]); } catch (\Exception $e) { $this->logger->critical($e); - $this->messageManager->addExceptionMessage($e, $e->getMessage()); + $this->messageManager->addExceptionMessage( + $e, + 'The order #' . $quote->getReservedOrderId() . ' cannot be processed.' + ); } return $resultRedirect->setPath('checkout/cart', ['_secure' => true]); diff --git a/app/code/Magento/Braintree/Model/Paypal/Helper/OrderPlace.php b/app/code/Magento/Braintree/Model/Paypal/Helper/OrderPlace.php index b833798eabf90..453ec439e8c27 100644 --- a/app/code/Magento/Braintree/Model/Paypal/Helper/OrderPlace.php +++ b/app/code/Magento/Braintree/Model/Paypal/Helper/OrderPlace.php @@ -5,14 +5,15 @@ */ namespace Magento\Braintree\Model\Paypal\Helper; -use Magento\Quote\Model\Quote; +use Magento\Braintree\Model\Paypal\OrderCancellationService; +use Magento\Checkout\Api\AgreementsValidatorInterface; use Magento\Checkout\Helper\Data; +use Magento\Checkout\Model\Type\Onepage; use Magento\Customer\Model\Group; use Magento\Customer\Model\Session; -use Magento\Checkout\Model\Type\Onepage; -use Magento\Quote\Api\CartManagementInterface; use Magento\Framework\Exception\LocalizedException; -use Magento\Checkout\Api\AgreementsValidatorInterface; +use Magento\Quote\Api\CartManagementInterface; +use Magento\Quote\Model\Quote; /** * Class OrderPlace @@ -41,23 +42,29 @@ class OrderPlace extends AbstractHelper private $checkoutHelper; /** - * Constructor - * + * @var OrderCancellationService + */ + private $orderCancellationService; + + /** * @param CartManagementInterface $cartManagement * @param AgreementsValidatorInterface $agreementsValidator * @param Session $customerSession * @param Data $checkoutHelper + * @param OrderCancellationService $orderCancellationService */ public function __construct( CartManagementInterface $cartManagement, AgreementsValidatorInterface $agreementsValidator, Session $customerSession, - Data $checkoutHelper + Data $checkoutHelper, + OrderCancellationService $orderCancellationService ) { $this->cartManagement = $cartManagement; $this->agreementsValidator = $agreementsValidator; $this->customerSession = $customerSession; $this->checkoutHelper = $checkoutHelper; + $this->orderCancellationService = $orderCancellationService; } /** @@ -66,7 +73,7 @@ public function __construct( * @param Quote $quote * @param array $agreement * @return void - * @throws LocalizedException + * @throws \Exception */ public function execute(Quote $quote, array $agreement) { @@ -81,7 +88,12 @@ public function execute(Quote $quote, array $agreement) $this->disabledQuoteAddressValidation($quote); $quote->collectTotals(); - $this->cartManagement->placeOrder($quote->getId()); + try { + $this->cartManagement->placeOrder($quote->getId()); + } catch (\Exception $e) { + $this->orderCancellationService->execute($quote->getReservedOrderId()); + throw $e; + } } /** diff --git a/app/code/Magento/Braintree/Model/Paypal/OrderCancellationService.php b/app/code/Magento/Braintree/Model/Paypal/OrderCancellationService.php new file mode 100644 index 0000000000000..ce39a5f875b47 --- /dev/null +++ b/app/code/Magento/Braintree/Model/Paypal/OrderCancellationService.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Braintree\Model\Paypal; + +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\OrderRepositoryInterface; + +/** + * The service to cancel an order and void authorization transaction. + */ +class OrderCancellationService +{ + /** + * @var OrderRepositoryInterface + */ + private $orderRepository; + + /** + * @var SearchCriteriaBuilder + */ + private $searchCriteriaBuilder; + + /** + * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param OrderRepositoryInterface $orderRepository + */ + public function __construct( + SearchCriteriaBuilder $searchCriteriaBuilder, + OrderRepositoryInterface $orderRepository + ) { + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->orderRepository = $orderRepository; + } + + /** + * Cancels an order and authorization transaction. + * + * @param string $incrementId + * @return bool + */ + public function execute($incrementId): bool + { + $order = $this->getOrder($incrementId); + if ($order === null) { + return false; + } + + // `\Magento\Sales\Model\Service\OrderService::cancel` cannot be used for cancellation as the service uses + // the order repository with outdated payment method instance (ex. contains Vault instead of Braintree) + $order->cancel(); + $this->orderRepository->save($order); + return true; + } + + /** + * Gets order by increment ID. + * + * @param string $incrementId + * @return OrderInterface|null + */ + private function getOrder(string $incrementId) + { + $searchCriteria = $this->searchCriteriaBuilder->addFilter(OrderInterface::INCREMENT_ID, $incrementId) + ->create(); + + $items = $this->orderRepository->getList($searchCriteria) + ->getItems(); + + return array_pop($items); + } +} diff --git a/app/code/Magento/Braintree/Plugin/OrderCancellation.php b/app/code/Magento/Braintree/Plugin/OrderCancellation.php new file mode 100644 index 0000000000000..eb126bce78dc8 --- /dev/null +++ b/app/code/Magento/Braintree/Plugin/OrderCancellation.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Braintree\Plugin; + +use Magento\Braintree\Model\Paypal\OrderCancellationService; +use Magento\Braintree\Model\Ui\ConfigProvider; +use Magento\Braintree\Model\Ui\PayPal\ConfigProvider as PayPalConfigProvider; +use Magento\Quote\Api\CartManagementInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\PaymentInterface; + +/** + * Cancels an order and an authorization transaction. + */ +class OrderCancellation +{ + /** + * @var OrderCancellationService + */ + private $orderCancellationService; + + /** + * @var CartRepositoryInterface + */ + private $quoteRepository; + + /** + * @param OrderCancellationService $orderCancellationService + * @param CartRepositoryInterface $quoteRepository + */ + public function __construct( + OrderCancellationService $orderCancellationService, + CartRepositoryInterface $quoteRepository + ) { + $this->orderCancellationService = $orderCancellationService; + $this->quoteRepository = $quoteRepository; + } + + /** + * Cancels an order if an exception occurs during the order creation. + * + * @param CartManagementInterface $subject + * @param \Closure $proceed + * @param int $cartId + * @param PaymentInterface $payment + * @return int + * @throws \Exception + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundPlaceOrder( + CartManagementInterface $subject, + \Closure $proceed, + $cartId, + PaymentInterface $payment = null + ) { + try { + return $proceed($cartId, $payment); + } catch (\Exception $e) { + $quote = $this->quoteRepository->get((int) $cartId); + $payment = $quote->getPayment(); + $paymentCodes = [ + ConfigProvider::CODE, + ConfigProvider::CC_VAULT_CODE, + PayPalConfigProvider::PAYPAL_CODE, + PayPalConfigProvider::PAYPAL_VAULT_CODE + ]; + if (in_array($payment->getMethod(), $paymentCodes)) { + $incrementId = $quote->getReservedOrderId(); + $this->orderCancellationService->execute($incrementId); + } + + throw $e; + } + } +} diff --git a/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/PlaceOrderTest.php b/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/PlaceOrderTest.php index 5a10b4abb3fbc..6f69e3b748e97 100644 --- a/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/PlaceOrderTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Controller/Paypal/PlaceOrderTest.php @@ -15,6 +15,8 @@ use Magento\Framework\Controller\ResultInterface; use Magento\Framework\Message\ManagerInterface; use Magento\Quote\Model\Quote; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; /** * Class PlaceOrderTest @@ -26,34 +28,34 @@ class PlaceOrderTest extends \PHPUnit\Framework\TestCase { /** - * @var OrderPlace|\PHPUnit_Framework_MockObject_MockObject + * @var OrderPlace|MockObject */ - private $orderPlaceMock; + private $orderPlace; /** - * @var Config|\PHPUnit_Framework_MockObject_MockObject + * @var Config|MockObject */ - private $configMock; + private $config; /** - * @var Session|\PHPUnit_Framework_MockObject_MockObject + * @var Session|MockObject */ - private $checkoutSessionMock; + private $checkoutSession; /** - * @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject + * @var RequestInterface|MockObject */ - private $requestMock; + private $request; /** - * @var ResultFactory|\PHPUnit_Framework_MockObject_MockObject + * @var ResultFactory|MockObject */ - private $resultFactoryMock; + private $resultFactory; /** - * @var ManagerInterface|\PHPUnit_Framework_MockObject_MockObject + * @var ManagerInterface|MockObject */ - protected $messageManagerMock; + private $messageManager; /** * @var PlaceOrder @@ -61,139 +63,143 @@ class PlaceOrderTest extends \PHPUnit\Framework\TestCase private $placeOrder; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MockObject */ - private $loggerMock; + private $logger; + /** + * @inheritdoc + */ protected function setUp() { - /** @var Context|\PHPUnit_Framework_MockObject_MockObject $contextMock */ - $contextMock = $this->getMockBuilder(Context::class) + /** @var Context|MockObject $context */ + $context = $this->getMockBuilder(Context::class) ->disableOriginalConstructor() ->getMock(); - $this->requestMock = $this->getMockBuilder(RequestInterface::class) + $this->request = $this->getMockBuilder(RequestInterface::class) ->setMethods(['getPostValue']) ->getMockForAbstractClass(); - $this->resultFactoryMock = $this->getMockBuilder(ResultFactory::class) + $this->resultFactory = $this->getMockBuilder(ResultFactory::class) ->disableOriginalConstructor() ->getMock(); - $this->checkoutSessionMock = $this->getMockBuilder(Session::class) + $this->checkoutSession = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() ->getMock(); - $this->configMock = $this->getMockBuilder(Config::class) + $this->config = $this->getMockBuilder(Config::class) ->disableOriginalConstructor() ->getMock(); - $this->orderPlaceMock = $this->getMockBuilder(OrderPlace::class) + $this->orderPlace = $this->getMockBuilder(OrderPlace::class) ->disableOriginalConstructor() ->getMock(); - $this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class) + $this->messageManager = $this->getMockBuilder(ManagerInterface::class) ->getMockForAbstractClass(); - $contextMock->expects(self::once()) - ->method('getRequest') - ->willReturn($this->requestMock); - $contextMock->expects(self::once()) - ->method('getResultFactory') - ->willReturn($this->resultFactoryMock); - $contextMock->expects(self::once()) - ->method('getMessageManager') - ->willReturn($this->messageManagerMock); - - $this->loggerMock = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + $context->method('getRequest') + ->willReturn($this->request); + $context->method('getResultFactory') + ->willReturn($this->resultFactory); + $context->method('getMessageManager') + ->willReturn($this->messageManager); + + $this->logger = $this->getMockBuilder(LoggerInterface::class) ->disableOriginalConstructor() ->getMock(); $this->placeOrder = new PlaceOrder( - $contextMock, - $this->configMock, - $this->checkoutSessionMock, - $this->orderPlaceMock, - $this->loggerMock + $context, + $this->config, + $this->checkoutSession, + $this->orderPlace, + $this->logger ); } + /** + * Checks if an order is placed successfully. + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NotFoundException + */ public function testExecute() { $agreement = ['test-data']; $quoteMock = $this->getQuoteMock(); - $quoteMock->expects(self::once()) - ->method('getItemsCount') + $quoteMock->method('getItemsCount') ->willReturn(1); $resultMock = $this->getResultMock(); - $resultMock->expects(self::once()) - ->method('setPath') + $resultMock->method('setPath') ->with('checkout/onepage/success') ->willReturnSelf(); - $this->resultFactoryMock->expects(self::once()) - ->method('create') + $this->resultFactory->method('create') ->with(ResultFactory::TYPE_REDIRECT) ->willReturn($resultMock); - $this->requestMock->expects(self::once()) - ->method('getPostValue') + $this->request->method('getPostValue') ->with('agreement', []) ->willReturn($agreement); - $this->checkoutSessionMock->expects(self::once()) - ->method('getQuote') + $this->checkoutSession->method('getQuote') ->willReturn($quoteMock); - $this->orderPlaceMock->expects(self::once()) - ->method('execute') + $this->orderPlace->method('execute') ->with($quoteMock, [0]); - $this->messageManagerMock->expects(self::never()) + $this->messageManager->expects(self::never()) ->method('addExceptionMessage'); self::assertEquals($this->placeOrder->execute(), $resultMock); } + /** + * Checks a negative scenario during place order action. + * + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NotFoundException + */ public function testExecuteException() { $agreement = ['test-data']; $quote = $this->getQuoteMock(); - $quote->expects(self::once()) - ->method('getItemsCount') + $quote->method('getItemsCount') ->willReturn(0); + $quote->method('getReservedOrderId') + ->willReturn('000000111'); $resultMock = $this->getResultMock(); - $resultMock->expects(self::once()) - ->method('setPath') + $resultMock->method('setPath') ->with('checkout/cart') ->willReturnSelf(); - $this->resultFactoryMock->expects(self::once()) - ->method('create') + $this->resultFactory->method('create') ->with(ResultFactory::TYPE_REDIRECT) ->willReturn($resultMock); - $this->requestMock->expects(self::once()) - ->method('getPostValue') + $this->request->method('getPostValue') ->with('agreement', []) ->willReturn($agreement); - $this->checkoutSessionMock->expects(self::once()) - ->method('getQuote') + $this->checkoutSession->method('getQuote') ->willReturn($quote); - $this->orderPlaceMock->expects(self::never()) + $this->orderPlace->expects(self::never()) ->method('execute'); - $this->messageManagerMock->expects(self::once()) - ->method('addExceptionMessage') + $this->messageManager->method('addExceptionMessage') ->with( self::isInstanceOf('\InvalidArgumentException'), - 'We can\'t initialize checkout.' + 'The order #000000111 cannot be processed.' ); self::assertEquals($this->placeOrder->execute(), $resultMock); } /** - * @return ResultInterface|\PHPUnit_Framework_MockObject_MockObject + * Gets mock object for a result. + * + * @return ResultInterface|MockObject */ private function getResultMock() { @@ -203,7 +209,9 @@ private function getResultMock() } /** - * @return Quote|\PHPUnit_Framework_MockObject_MockObject + * Gets mock object for a quote. + * + * @return Quote|MockObject */ private function getQuoteMock() { diff --git a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/OrderPlaceTest.php b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/OrderPlaceTest.php index 1aecba91b9afc..ac6351e0b8f1f 100644 --- a/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/OrderPlaceTest.php +++ b/app/code/Magento/Braintree/Test/Unit/Model/Paypal/Helper/OrderPlaceTest.php @@ -3,9 +3,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Braintree\Test\Unit\Model\Paypal\Helper; use Magento\Braintree\Model\Paypal\Helper\OrderPlace; +use Magento\Braintree\Model\Paypal\OrderCancellationService; use Magento\Checkout\Api\AgreementsValidatorInterface; use Magento\Checkout\Helper\Data; use Magento\Checkout\Model\Type\Onepage; @@ -14,6 +16,7 @@ use Magento\Quote\Api\CartManagementInterface; use Magento\Quote\Model\Quote; use Magento\Quote\Model\Quote\Address; +use PHPUnit\Framework\MockObject\MockObject; /** * Class OrderPlaceTest @@ -27,62 +30,80 @@ class OrderPlaceTest extends \PHPUnit\Framework\TestCase const TEST_EMAIL = 'test@test.loc'; /** - * @var CartManagementInterface|\PHPUnit_Framework_MockObject_MockObject + * @var CartManagementInterface|MockObject */ - private $cartManagementMock; + private $cartManagement; /** - * @var AgreementsValidatorInterface|\PHPUnit_Framework_MockObject_MockObject + * @var AgreementsValidatorInterface|MockObject */ - private $agreementsValidatorMock; + private $agreementsValidator; /** - * @var Session|\PHPUnit_Framework_MockObject_MockObject + * @var Session|MockObject */ - private $customerSessionMock; + private $customerSession; /** - * @var Data|\PHPUnit_Framework_MockObject_MockObject + * @var Data|MockObject */ - private $checkoutHelperMock; + private $checkoutHelper; /** - * @var Address|\PHPUnit_Framework_MockObject_MockObject + * @var Address|MockObject */ - private $billingAddressMock; + private $billingAddress; /** * @var OrderPlace */ private $orderPlace; + /** + * @var OrderCancellationService|MockObject + */ + private $orderCancellation; + + /** + * @inheritdoc + */ protected function setUp() { - $this->cartManagementMock = $this->getMockBuilder(CartManagementInterface::class) + $this->cartManagement = $this->getMockBuilder(CartManagementInterface::class) ->getMockForAbstractClass(); - $this->agreementsValidatorMock = $this->getMockBuilder(AgreementsValidatorInterface::class) + $this->agreementsValidator = $this->getMockBuilder(AgreementsValidatorInterface::class) ->getMockForAbstractClass(); - $this->customerSessionMock = $this->getMockBuilder(Session::class) + $this->customerSession = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->getMock(); + $this->checkoutHelper = $this->getMockBuilder(Data::class) ->disableOriginalConstructor() ->getMock(); - $this->checkoutHelperMock = $this->getMockBuilder(Data::class) + + $this->orderCancellation = $this->getMockBuilder(OrderCancellationService::class) ->disableOriginalConstructor() ->getMock(); $this->orderPlace = new OrderPlace( - $this->cartManagementMock, - $this->agreementsValidatorMock, - $this->customerSessionMock, - $this->checkoutHelperMock + $this->cartManagement, + $this->agreementsValidator, + $this->customerSession, + $this->checkoutHelper, + $this->orderCancellation ); } + /** + * Checks a scenario for a guest customer. + * + * @throws \Exception + */ public function testExecuteGuest() { $agreement = ['test', 'test']; $quoteMock = $this->getQuoteMock(); - $this->agreementsValidatorMock->expects(self::once()) + $this->agreementsValidator->expects(self::once()) ->method('isValid') ->willReturn(true); @@ -97,7 +118,7 @@ public function testExecuteGuest() ->method('getId') ->willReturn(10); - $this->cartManagementMock->expects(self::once()) + $this->cartManagement->expects(self::once()) ->method('placeOrder') ->with(10); @@ -105,9 +126,11 @@ public function testExecuteGuest() } /** - * @param \PHPUnit_Framework_MockObject_MockObject $quoteMock + * Disables address validation. + * + * @param MockObject $quoteMock */ - private function disabledQuoteAddressValidationStep(\PHPUnit_Framework_MockObject_MockObject $quoteMock) + private function disabledQuoteAddressValidationStep($quoteMock) { $billingAddressMock = $this->getBillingAddressMock($quoteMock); $shippingAddressMock = $this->getMockBuilder(Address::class) @@ -115,26 +138,21 @@ private function disabledQuoteAddressValidationStep(\PHPUnit_Framework_MockObjec ->disableOriginalConstructor() ->getMock(); - $quoteMock->expects(self::once()) - ->method('getShippingAddress') + $quoteMock->method('getShippingAddress') ->willReturn($shippingAddressMock); - $billingAddressMock->expects(self::once()) - ->method('setShouldIgnoreValidation') + $billingAddressMock->method('setShouldIgnoreValidation') ->with(true) ->willReturnSelf(); - $quoteMock->expects(self::once()) - ->method('getIsVirtual') + $quoteMock->method('getIsVirtual') ->willReturn(false); - $shippingAddressMock->expects(self::once()) - ->method('setShouldIgnoreValidation') + $shippingAddressMock->method('setShouldIgnoreValidation') ->with(true) ->willReturnSelf(); - $billingAddressMock->expects(self::any()) - ->method('getEmail') + $billingAddressMock->method('getEmail') ->willReturn(self::TEST_EMAIL); $billingAddressMock->expects(self::never()) @@ -142,25 +160,24 @@ private function disabledQuoteAddressValidationStep(\PHPUnit_Framework_MockObjec } /** - * @param \PHPUnit_Framework_MockObject_MockObject $quoteMock + * Prepares checkout step. + * + * @param MockObject $quoteMock */ - private function getCheckoutMethodStep(\PHPUnit_Framework_MockObject_MockObject $quoteMock) + private function getCheckoutMethodStep($quoteMock) { - $this->customerSessionMock->expects(self::once()) - ->method('isLoggedIn') + $this->customerSession->method('isLoggedIn') ->willReturn(false); $quoteMock->expects(self::at(1)) ->method('getCheckoutMethod') ->willReturn(null); - $this->checkoutHelperMock->expects(self::once()) - ->method('isAllowedGuestCheckout') + $this->checkoutHelper->method('isAllowedGuestCheckout') ->with($quoteMock) ->willReturn(true); - $quoteMock->expects(self::once()) - ->method('setCheckoutMethod') + $quoteMock->method('setCheckoutMethod') ->with(Onepage::METHOD_GUEST); $quoteMock->expects(self::at(2)) @@ -169,9 +186,11 @@ private function getCheckoutMethodStep(\PHPUnit_Framework_MockObject_MockObject } /** - * @param \PHPUnit_Framework_MockObject_MockObject $quoteMock + * Prepares quote. + * + * @param MockObject $quoteMock */ - private function prepareGuestQuoteStep(\PHPUnit_Framework_MockObject_MockObject $quoteMock) + private function prepareGuestQuoteStep($quoteMock) { $billingAddressMock = $this->getBillingAddressMock($quoteMock); @@ -184,44 +203,44 @@ private function prepareGuestQuoteStep(\PHPUnit_Framework_MockObject_MockObject ->method('getEmail') ->willReturn(self::TEST_EMAIL); - $quoteMock->expects(self::once()) - ->method('setCustomerEmail') + $quoteMock->method('setCustomerEmail') ->with(self::TEST_EMAIL) ->willReturnSelf(); - $quoteMock->expects(self::once()) - ->method('setCustomerIsGuest') + $quoteMock->method('setCustomerIsGuest') ->with(true) ->willReturnSelf(); - $quoteMock->expects(self::once()) - ->method('setCustomerGroupId') + $quoteMock->method('setCustomerGroupId') ->with(Group::NOT_LOGGED_IN_ID) ->willReturnSelf(); } /** - * @param \PHPUnit_Framework_MockObject_MockObject $quoteMock - * @return Address|\PHPUnit_Framework_MockObject_MockObject + * Gets a mock object for a billing address entity. + * + * @param MockObject $quoteMock + * @return Address|MockObject */ - private function getBillingAddressMock(\PHPUnit_Framework_MockObject_MockObject $quoteMock) + private function getBillingAddressMock($quoteMock) { - if (!isset($this->billingAddressMock)) { - $this->billingAddressMock = $this->getMockBuilder(Address::class) + if (!isset($this->billingAddress)) { + $this->billingAddress = $this->getMockBuilder(Address::class) ->setMethods(['setShouldIgnoreValidation', 'getEmail', 'setSameAsBilling']) ->disableOriginalConstructor() ->getMock(); } - $quoteMock->expects(self::any()) - ->method('getBillingAddress') - ->willReturn($this->billingAddressMock); + $quoteMock->method('getBillingAddress') + ->willReturn($this->billingAddress); - return $this->billingAddressMock; + return $this->billingAddress; } /** - * @return Quote|\PHPUnit_Framework_MockObject_MockObject + * Gets a mock object for a quote. + * + * @return Quote|MockObject */ private function getQuoteMock() { diff --git a/app/code/Magento/Braintree/etc/di.xml b/app/code/Magento/Braintree/etc/di.xml index c5440db1889f4..901b30cb41d2c 100644 --- a/app/code/Magento/Braintree/etc/di.xml +++ b/app/code/Magento/Braintree/etc/di.xml @@ -624,4 +624,8 @@ </argument> </arguments> </type> + + <type name="Magento\Quote\Api\CartManagementInterface"> + <plugin name="order_cancellation" type="Magento\Braintree\Plugin\OrderCancellation"/> + </type> </config> diff --git a/app/code/Magento/Braintree/i18n/en_US.csv b/app/code/Magento/Braintree/i18n/en_US.csv index 7bd305f546dc6..e9145b35b56ef 100644 --- a/app/code/Magento/Braintree/i18n/en_US.csv +++ b/app/code/Magento/Braintree/i18n/en_US.csv @@ -193,3 +193,4 @@ Currency,Currency "Too many concurrent attempts to void this transaction. Try again later.","Too many concurrent attempts to void this transaction. Try again later." "Braintree Settlement","Braintree Settlement" "The Payment Token is not available to perform the request.","The Payment Token is not available to perform the request." +"The order #%1 cannot be processed.","The order #%1 cannot be processed." diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Controller/Paypal/PlaceOrderTest.php b/dev/tests/integration/testsuite/Magento/Braintree/Controller/Paypal/PlaceOrderTest.php new file mode 100644 index 0000000000000..4f2b0fd67840d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/Controller/Paypal/PlaceOrderTest.php @@ -0,0 +1,173 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\Braintree\Controller\Paypal; + +use Braintree\Result\Successful; +use Braintree\Transaction; +use Magento\Braintree\Model\Adapter\BraintreeAdapter; +use Magento\Braintree\Model\Adapter\BraintreeAdapterFactory; +use Magento\Checkout\Model\Session; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\App\Request\Http as HttpRequest; +use Magento\Framework\Message\MessageInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\Data\CartInterface; +use Magento\Sales\Api\Data\OrderInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\TestFramework\TestCase\AbstractController; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * PlaceOrderTest + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class PlaceOrderTest extends AbstractController +{ + /** + * @var Session|MockObject + */ + private $session; + + /** + * @var BraintreeAdapter|MockObject + */ + private $adapter; + + /** + * @inheritdoc + */ + protected function setUp() + { + parent::setUp(); + + $this->session = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods(['getQuote', 'setLastOrderStatus', 'unsLastBillingAgreementReferenceId']) + ->getMock(); + + $adapterFactory = $this->getMockBuilder(BraintreeAdapterFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->adapter = $this->getMockBuilder(BraintreeAdapter::class) + ->disableOriginalConstructor() + ->getMock(); + $adapterFactory->method('create') + ->willReturn($this->adapter); + + $this->_objectManager->addSharedInstance($this->session, Session::class); + $this->_objectManager->addSharedInstance($adapterFactory, BraintreeAdapterFactory::class); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->_objectManager->removeSharedInstance(Session::class); + $this->_objectManager->removeSharedInstance(BraintreeAdapterFactory::class); + parent::tearDown(); + } + + /** + * Tests a negative scenario for a place order flow when exception throws after placing an order. + * + * @magentoDataFixture Magento/Braintree/Fixtures/paypal_quote.php + */ + public function testExecuteWithFailedOrder() + { + $reservedOrderId = 'test01'; + $quote = $this->getQuote($reservedOrderId); + + $this->session->method('getQuote') + ->willReturn($quote); + + $this->adapter->method('sale') + ->willReturn($this->getTransactionStub('authorized')); + $this->adapter->method('void') + ->willReturn($this->getTransactionStub('voided')); + + // emulates an error after placing the order + $this->session->method('setLastOrderStatus') + ->willThrowException(new \Exception('Test Exception')); + + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->dispatch('braintree/paypal/placeOrder'); + + self::assertRedirect(self::stringContains('checkout/cart')); + self::assertSessionMessages( + self::equalTo(['The order #' . $reservedOrderId . ' cannot be processed.']), + MessageInterface::TYPE_ERROR + ); + + $order = $this->getOrder($reservedOrderId); + self::assertEquals('canceled', $order->getState()); + } + + /** + * Gets quote by reserved order ID. + * + * @param string $reservedOrderId + * @return CartInterface + */ + private function getQuote(string $reservedOrderId): CartInterface + { + $searchCriteria = $this->_objectManager->get(SearchCriteriaBuilder::class) + ->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->_objectManager->get(CartRepositoryInterface::class); + $items = $quoteRepository->getList($searchCriteria) + ->getItems(); + + return array_pop($items); + } + + /** + * Gets order by increment ID. + * + * @param string $incrementId + * @return OrderInterface + */ + private function getOrder(string $incrementId): OrderInterface + { + $searchCriteria = $this->_objectManager->get(SearchCriteriaBuilder::class) + ->addFilter('increment_id', $incrementId) + ->create(); + + /** @var OrderRepositoryInterface $repository */ + $repository = $this->_objectManager->get(OrderRepositoryInterface::class); + $items = $repository->getList($searchCriteria) + ->getItems(); + + return array_pop($items); + } + + /** + * Creates stub for Braintree Transaction. + * + * @param string $status + * @return Successful + */ + private function getTransactionStub(string $status): Successful + { + $transaction = $this->getMockBuilder(Transaction::class) + ->disableOriginalConstructor() + ->getMock(); + $transaction->status = $status; + $transaction->paypal = [ + 'paymentId' => 'pay-001', + 'payerEmail' => 'test@test.com' + ]; + $response = new Successful(); + $response->success = true; + $response->transaction = $transaction; + + return $response; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote.php b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote.php new file mode 100644 index 0000000000000..d0db6233f05b1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Braintree\Model\Ui\PayPal\ConfigProvider; +use Magento\Quote\Api\CartRepositoryInterface; + +require __DIR__ . '/../_files/paypal_vault_token.php'; +require __DIR__ . '/../../Sales/_files/quote_with_customer.php'; + +$quote->getShippingAddress() + ->setShippingMethod('flatrate_flatrate') + ->setCollectShippingRates(true); +$quote->getPayment() + ->setMethod(ConfigProvider::PAYPAL_VAULT_CODE) + ->setAdditionalInformation( + [ + 'customer_id' => $quote->getCustomerId(), + 'public_hash' => $paymentToken->getPublicHash() + ] + ); + +$quote->collectTotals(); + +/** @var CartRepositoryInterface $quoteRepository */ +$quoteRepository = $objectManager->get(CartRepositoryInterface::class); +$quoteRepository->save($quote); diff --git a/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote_rollback.php b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote_rollback.php new file mode 100644 index 0000000000000..5d0fa8cca85d9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Braintree/Fixtures/paypal_quote_rollback.php @@ -0,0 +1,9 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +require __DIR__ . '/../../Sales/_files/quote_with_customer_rollback.php'; diff --git a/lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php b/lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php new file mode 100644 index 0000000000000..a4b87ecfe8452 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\Framework\App\Action; + +use Magento\Framework\App\ActionInterface; + +/** + * Marker for actions processing POST requests. + */ +interface HttpPostActionInterface extends ActionInterface +{ + +} From 07e0adb8bb242f7ff459c8540ab655e06b8f9172 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Mon, 3 Dec 2018 15:09:52 +0200 Subject: [PATCH 49/88] MAGETWO-95653: Product positions are incorrect after import --- .../Catalog/_files/category_product.php | 2 +- .../Model/Import/ProductTest.php | 68 +++++++++++++++++++ .../product_to_import_with_category.csv | 2 + 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_to_import_with_category.csv diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product.php index 6803d96f0c0de..fe61b3e197ca0 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/category_product.php @@ -15,7 +15,7 @@ )->setParentId( 2 )->setPath( - '1/2/3' + '1/2/333' )->setLevel( 2 )->setAvailableSortBy( diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index f3cb01a9bbe2e..2aef07fbf5283 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -69,6 +69,11 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase */ private $logger; + /** + * @var \Magento\Framework\EntityManager\EntityMetadata + */ + private $metadata; + protected function setUp() { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -79,6 +84,12 @@ protected function setUp() \Magento\CatalogImportExport\Model\Import\Product::class, ['logger' => $this->logger] ); + + $metadataPool = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Framework\EntityManager\MetadataPool::class + ); + $this->metadata = $metadataPool->getMetadata(ProductInterface::class); + parent::setUp(); } @@ -1278,6 +1289,63 @@ public function testProductPositionInCategory() } } + /** + * @magentoAppArea adminhtml + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + * @magentoDataFixture Magento/Catalog/_files/category_product.php + */ + public function testNewProductPositionInCategory() + { + $categoryId = 333; + + $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\Framework\Filesystem::class + ); + + $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); + $source = $this->objectManager->create( + \Magento\ImportExport\Model\Import\Source\Csv::class, + [ + 'file' => __DIR__ . '/_files/product_to_import_with_category.csv', + 'directory' => $directory + ] + ); + $errors = $this->_model->setSource( + $source + )->setParameters( + [ + 'behavior' => \Magento\ImportExport\Model\Import::BEHAVIOR_APPEND, + 'entity' => 'catalog_product', + ] + )->validateData(); + + $this->assertTrue($errors->getErrorsCount() == 0); + $this->_model->importData(); + + /** @var \Magento\Framework\App\ResourceConnection $resourceConnection */ + $resourceConnection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + \Magento\Framework\App\ResourceConnection::class + ); + $linkField = $this->metadata->getLinkField(); + $categoryProductstableName = $resourceConnection->getTableName('catalog_category_product'); + $productEntitiesTableName = $resourceConnection->getTableName('catalog_product_entity'); + $select = $resourceConnection->getConnection() + ->select() + ->from(['category_products' => $categoryProductstableName]) + ->join( + ['product_entities' => $productEntitiesTableName], + 'product_entities.' . $linkField . ' = category_products.product_id', + '' + ) + ->where('category_products.category_id = ?', $categoryId) + ->where('product_entities.sku = "simpleImported"'); + $importedItem = $resourceConnection->getConnection()->fetchRow($select); + $this->assertTrue(is_array($importedItem)); + $this->assertNotEmpty($importedItem); + $this->assertEquals(0, $importedItem['position']); + } + /** * @return array */ diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_to_import_with_category.csv b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_to_import_with_category.csv new file mode 100644 index 0000000000000..2bab84ec1ca57 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/_files/product_to_import_with_category.csv @@ -0,0 +1,2 @@ +sku,product_type,store_view_code,name,price,attribute_set_code,categories +simpleImported,simple,,"simple Imported",25,Default,"Default Category/Category 1" From 1f5d7082ed2333a7e7e484a4e01709d68f31a9e5 Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Mon, 3 Dec 2018 15:57:46 +0200 Subject: [PATCH 50/88] MAGETWO-95653: Product positions are incorrect after import --- .../CatalogImportExport/Model/Import/ProductTest.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 2aef07fbf5283..027f2558aaf00 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -70,10 +70,8 @@ class ProductTest extends \Magento\TestFramework\Indexer\TestCase private $logger; /** - * @var \Magento\Framework\EntityManager\EntityMetadata + * @inheritdoc */ - private $metadata; - protected function setUp() { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -85,11 +83,6 @@ protected function setUp() ['logger' => $this->logger] ); - $metadataPool = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Framework\EntityManager\MetadataPool::class - ); - $this->metadata = $metadataPool->getMetadata(ProductInterface::class); - parent::setUp(); } @@ -1327,7 +1320,6 @@ public function testNewProductPositionInCategory() $resourceConnection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( \Magento\Framework\App\ResourceConnection::class ); - $linkField = $this->metadata->getLinkField(); $categoryProductstableName = $resourceConnection->getTableName('catalog_category_product'); $productEntitiesTableName = $resourceConnection->getTableName('catalog_product_entity'); $select = $resourceConnection->getConnection() @@ -1335,7 +1327,7 @@ public function testNewProductPositionInCategory() ->from(['category_products' => $categoryProductstableName]) ->join( ['product_entities' => $productEntitiesTableName], - 'product_entities.' . $linkField . ' = category_products.product_id', + 'product_entities.entity_id = category_products.product_id', '' ) ->where('category_products.category_id = ?', $categoryId) From 868b04520151ef0f1e68fe160ebb99b8cea0f9dd Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Mon, 3 Dec 2018 16:22:56 +0200 Subject: [PATCH 51/88] MAGETWO-89397: Wrong Checkout Totals Sort Order in cart --- .../Test/Mftf/ActionGroup/CheckoutActionGroup.xml | 8 -------- .../Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml | 7 ++----- .../Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml | 2 +- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index 08679765f5eb2..aa168899ddb02 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml @@ -73,12 +73,4 @@ <conditionalClick selector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" dependentSelector="{{CheckoutShippingMethodsSection.checkShippingMethodByName('Flat Rate')}}" visible="true" stepKey="selectFlatRateShippingMethod"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskForNextButton"/> </actionGroup> - - <actionGroup name="CheckTotalsSortOrderInSummarySection"> - <arguments> - <argument name="elementName" type="string"/> - <argument name="positionNumber" type="integer"/> - </arguments> - <see userInput="{{elementName}}" selector="{{StorefrontCheckoutCartSummarySection.totalsElementByPosition(positionNumber)}}" stepKey="assertElementPosition"/> - </actionGroup> </actionGroups> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml index 872ee9fb16ff5..11aae024d2e0a 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutTotalsSortOrderInCartTest.xml @@ -22,7 +22,7 @@ <createData entity="SimpleProduct" stepKey="createProduct"> <requiredEntity createDataKey="createCategory"/> </createData> - <createData entity="ApiCartRule1" stepKey="createCartRule"/> + <createData entity="SaleRule50PercentDiscountNoCoupon" stepKey="createCartRule"/> <createData entity="CheckoutShippingTotalsSortOrder" stepKey="setConfigShippingTotalsSortOrder"/> </before> @@ -41,9 +41,6 @@ <argument name="expectedDiscount" value="-$100"/> </actionGroup> - <actionGroup ref="CheckTotalsSortOrderInSummarySection" stepKey="checkTotalsSortOrderInSummarySection"> - <argument name="elementName" value="Shipping (Flat Rate - Fixed)"/> - <argument name="positionNumber" value="3"/> - </actionGroup> + <see userInput="Shipping (Flat Rate - Fixed)" selector="{{StorefrontCheckoutCartSummarySection.totalsElementByPosition('3')}}" stepKey="assertElementPosition"/> </test> </tests> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml index 764fe16db552a..359edf3664cb2 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml @@ -85,7 +85,7 @@ <entity name="SalesRule100PercentDiscount" extends="TestSalesRule" type="SalesRule"> <data key="discountAmount">100</data> </entity> - <entity name="ApiCartRule1" type="SalesRule"> + <entity name="SaleRule50PercentDiscountNoCoupon" type="SalesRule"> <data key="name" unique="suffix">salesRule</data> <data key="description">Sales Rule Descritpion</data> <array key="website_ids"> From a2ac9be488dfd1e65448f6e9f9161317fa379a5a Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 3 Dec 2018 17:12:10 +0200 Subject: [PATCH 52/88] MAGETWO-94455: User agent exception not setting the correct templates for product pages --- .../Product/Listing/Collector/ImageTest.php | 20 ++++++++++++++----- .../Product/Listing/Collector/Image.php | 17 ++++++++++++++-- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php index 12bc9acfa4c51..16923fb16e790 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php @@ -6,15 +6,16 @@ namespace Magento\Catalog\Test\Unit\Ui\DataProvider\Product\Listing\Collector; +use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Api\Data\ProductRender\ImageInterface; use Magento\Catalog\Api\Data\ProductRenderInterface; +use Magento\Catalog\Helper\Image as ImageHelper; +use Magento\Catalog\Helper\ImageFactory; use Magento\Catalog\Model\Product; -use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Ui\DataProvider\Product\Listing\Collector\Image; use Magento\Framework\View\DesignInterface; +use Magento\Framework\View\DesignLoader; use Magento\Store\Model\StoreManagerInterface; -use Magento\Catalog\Helper\ImageFactory; -use Magento\Catalog\Api\Data\ProductRender\ImageInterface; -use Magento\Catalog\Helper\Image as ImageHelper; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -42,6 +43,12 @@ class ImageTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Catalog\Api\Data\ProductRender\ImageInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject */ private $imageInterfaceFactory; + /** @var DesignLoader|\PHPUnit_Framework_MockObject_MockObject */ + private $designLoader; + + /** + * @inheritdoc + */ public function setUp() { $this->imageFactory = $this->getMockBuilder(ImageFactory::class) @@ -60,13 +67,15 @@ public function setUp() ->getMock(); $this->storeManager = $this->createMock(StoreManagerInterface::class); $this->design = $this->createMock(DesignInterface::class); + $this->designLoader = $this->createMock(DesignLoader::class); $this->model = new Image( $this->imageFactory, $this->state, $this->storeManager, $this->design, $this->imageInterfaceFactory, - $this->imageCodes + $this->imageCodes, + $this->designLoader ); } @@ -165,6 +174,7 @@ public function testEmulateImageCreating() $imageMock->expects($this->once()) ->method('setUrl') ->with('url'); + $this->designLoader->expects($this->once())->method('load'); $this->assertEquals( $imageHelperMock, diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php index 216bc16968fcb..34879ab29c185 100644 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Listing/Collector/Image.php @@ -17,12 +17,14 @@ use Magento\Framework\View\DesignInterface; use Magento\Store\Model\StoreManager; use Magento\Store\Model\StoreManagerInterface; +use Magento\Framework\View\DesignLoader; /** * Collect enough information about image rendering on front * If you want to add new image, that should render on front you need * to configure this class in di.xml * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Image implements ProductRenderCollectorInterface { @@ -59,6 +61,11 @@ class Image implements ProductRenderCollectorInterface */ private $imageRenderInfoFactory; + /** + * @var DesignLoader + */ + private $designLoader; + /** * Image constructor. * @param ImageFactory $imageFactory @@ -67,6 +74,7 @@ class Image implements ProductRenderCollectorInterface * @param DesignInterface $design * @param ImageInterfaceFactory $imageRenderInfoFactory * @param array $imageCodes + * @param DesignLoader|null $designLoader */ public function __construct( ImageFactory $imageFactory, @@ -74,7 +82,8 @@ public function __construct( StoreManagerInterface $storeManager, DesignInterface $design, ImageInterfaceFactory $imageRenderInfoFactory, - array $imageCodes = [] + array $imageCodes = [], + DesignLoader $designLoader = null ) { $this->imageFactory = $imageFactory; $this->imageCodes = $imageCodes; @@ -82,6 +91,8 @@ public function __construct( $this->storeManager = $storeManager; $this->design = $design; $this->imageRenderInfoFactory = $imageRenderInfoFactory; + $this->designLoader = $designLoader ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(DesignLoader::class); } /** @@ -124,6 +135,8 @@ public function collect(ProductInterface $product, ProductRenderInterface $produ } /** + * Callback for emulating image creation. + * * Callback in which we emulate initialize default design theme, depends on current store, be settings store id * from render info * @@ -136,7 +149,7 @@ public function collect(ProductInterface $product, ProductRenderInterface $produ public function emulateImageCreating(ProductInterface $product, $imageCode, $storeId, ImageInterface $image) { $this->storeManager->setCurrentStore($storeId); - $this->design->setDefaultDesignTheme(); + $this->designLoader->load(); $imageHelper = $this->imageFactory->create(); $imageHelper->init($product, $imageCode); From c6b8a27e2f25b180feb0bf6e8576c128fc1ec60f Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Tue, 4 Dec 2018 00:41:20 -0800 Subject: [PATCH 53/88] MAGETWO-91122: Html attributes auto removed from WYSIWYG Editor --- lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js index 98ce6a005db04..b73aa1b7e1473 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js @@ -149,7 +149,8 @@ define([ ['col', 'width align char charoff valign'], ['input button select textarea', 'autofocus'], ['input textarea', 'placeholder onselect onchange onfocus onblur'], - ['link script img', 'crossorigin'] + ['link script img', 'crossorigin'], + ['div','aria-role'], ]; rawData.forEach(function (data) { From a98ec5066892afaee8008216ad16592ac667be69 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Tue, 4 Dec 2018 11:17:08 +0200 Subject: [PATCH 54/88] MAGETWO-96587: Investigation an issue that an exception appears after an order has been payed --- .../Controller/Paypal/PlaceOrder.php | 3 +-- .../App/Action/HttpPostActionInterface.php | 19 ------------------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php diff --git a/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php b/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php index 418cb93900610..1440d495e8a7d 100644 --- a/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php +++ b/app/code/Magento/Braintree/Controller/Paypal/PlaceOrder.php @@ -9,7 +9,6 @@ use Magento\Braintree\Model\Paypal\Helper; use Magento\Checkout\Model\Session; use Magento\Framework\App\Action\Context; -use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\ObjectManager; use Magento\Framework\Controller\ResultFactory; use Magento\Framework\Exception\LocalizedException; @@ -18,7 +17,7 @@ /** * Class PlaceOrder */ -class PlaceOrder extends AbstractAction implements HttpPostActionInterface +class PlaceOrder extends AbstractAction { /** * @var Helper\OrderPlace diff --git a/lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php b/lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php deleted file mode 100644 index a4b87ecfe8452..0000000000000 --- a/lib/internal/Magento/Framework/App/Action/HttpPostActionInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -declare(strict_types=1); - -namespace Magento\Framework\App\Action; - -use Magento\Framework\App\ActionInterface; - -/** - * Marker for actions processing POST requests. - */ -interface HttpPostActionInterface extends ActionInterface -{ - -} From 06ffdcd001e2deff9b6cba8be8fcd006a4e6214e Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 4 Dec 2018 11:34:25 +0200 Subject: [PATCH 55/88] MAGETWO-86477: [2.2] Expose Authorize.net Response Codes in Checkout --- .../Payment/view/frontend/templates/transparent/iframe.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml index 163aaf979ec2e..afa71fe591495 100644 --- a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml +++ b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml @@ -40,7 +40,7 @@ $params = $block->getParams(); $(parent).trigger('clearTimeout'); fullScreenLoader.stopLoader(); globalMessageList.addErrorMessage({ - message: $t('An error occurred on the server. Please try to place the order again.') + message: $t(<?= /* @escapeNotVerified */ json_encode($params['error_msg'])?>) }); } ); From f08c195a73aee43539fc007752ac66c541229f23 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 4 Dec 2018 11:40:38 +0200 Subject: [PATCH 56/88] MAGETWO-94455: User agent exception not setting the correct templates for product pages --- .../Product/Listing/Collector/ImageTest.php | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php index 16923fb16e790..2d6b082e35b17 100644 --- a/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Ui/DataProvider/Product/Listing/Collector/ImageTest.php @@ -46,11 +46,18 @@ class ImageTest extends \PHPUnit\Framework\TestCase /** @var DesignLoader|\PHPUnit_Framework_MockObject_MockObject */ private $designLoader; + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ + protected $objectManager; + /** * @inheritdoc */ public function setUp() { + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->imageFactory = $this->getMockBuilder(ImageFactory::class) ->disableOriginalConstructor() ->getMock(); @@ -68,15 +75,20 @@ public function setUp() $this->storeManager = $this->createMock(StoreManagerInterface::class); $this->design = $this->createMock(DesignInterface::class); $this->designLoader = $this->createMock(DesignLoader::class); - $this->model = new Image( - $this->imageFactory, - $this->state, - $this->storeManager, - $this->design, - $this->imageInterfaceFactory, - $this->imageCodes, - $this->designLoader - ); + + $this->model = $this->objectManager + ->getObject( + Image::class, + [ + 'imageFactory' => $this->imageFactory, + 'state' => $this->state, + 'storeManager' => $this->storeManager, + 'design' => $this->design, + 'imageRenderInfoFactory' => $this->imageInterfaceFactory, + 'imageCodes' => $this->imageCodes, + 'designLoader' => $this->designLoader, + ] + ); } public function testGet() From a08768e00fc46058a26af06a7359245a8d4d6393 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Tue, 4 Dec 2018 02:07:59 -0800 Subject: [PATCH 57/88] MAGETWO-91122: Html attributes auto removed from WYSIWYG Editor --- lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js index b73aa1b7e1473..41def246989db 100644 --- a/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js +++ b/lib/web/mage/adminhtml/wysiwyg/tiny_mce/html5-schema.js @@ -150,7 +150,7 @@ define([ ['input button select textarea', 'autofocus'], ['input textarea', 'placeholder onselect onchange onfocus onblur'], ['link script img', 'crossorigin'], - ['div','aria-role'], + ['div','aria-role'] ]; rawData.forEach(function (data) { From 49b6cd42c268c3ec6a8121400e2a2fd1188ca4ad Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Tue, 4 Dec 2018 15:48:17 +0200 Subject: [PATCH 58/88] MAGETWO-96394: Wrong price calculation for bundle product on creating order from the admin panel --- .../Fieldset/Options/Type/Checkbox.php | 15 ++- .../Composite/Fieldset/Options/Type/Multi.php | 15 ++- .../Magento/Bundle/Model/Product/Type.php | 2 +- .../ActionGroup/AdminOrderActionGroup.xml | 29 +++++ .../AdminOrderFormBundleProductSection.xml | 15 +++ .../Section/AdminOrderFormItemsSection.xml | 1 + .../AdminCreateOrderWithBundleProductTest.xml | 111 ++++++++++++++++++ 7 files changed, 181 insertions(+), 7 deletions(-) create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBundleProductSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithBundleProductTest.xml diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Checkbox.php b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Checkbox.php index b220e2c98d77c..46db8a9907341 100644 --- a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Checkbox.php +++ b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Checkbox.php @@ -20,9 +20,7 @@ class Checkbox extends \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Op protected $_template = 'Magento_Bundle::product/composite/fieldset/options/type/checkbox.phtml'; /** - * @param string $elementId - * @param string $containerId - * @return string + * @inheritdoc */ public function setValidationContainer($elementId, $containerId) { @@ -34,4 +32,15 @@ public function setValidationContainer($elementId, $containerId) '\'; </script>'; } + + /** + * @inheritdoc + */ + public function getSelectionPrice($selection) + { + $price = parent::getSelectionPrice($selection); + $qty = $selection->getSelectionQty(); + + return $price * $qty; + } } diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Multi.php b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Multi.php index a4b8c6bde73aa..629f08dc75106 100644 --- a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Multi.php +++ b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Composite/Fieldset/Options/Type/Multi.php @@ -20,9 +20,7 @@ class Multi extends \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Optio protected $_template = 'Magento_Bundle::product/composite/fieldset/options/type/multi.phtml'; /** - * @param string $elementId - * @param string $containerId - * @return string + * @inheritdoc */ public function setValidationContainer($elementId, $containerId) { @@ -34,4 +32,15 @@ public function setValidationContainer($elementId, $containerId) '\'; </script>'; } + + /** + * @inheritdoc + */ + public function getSelectionPrice($selection) + { + $price = parent::getSelectionPrice($selection); + $qty = $selection->getSelectionQty(); + + return $price * $qty; + } } diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index fd024fa87109e..a497597ee6fb1 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -739,7 +739,7 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p * for selection (not for all bundle) */ $price = $product->getPriceModel() - ->getSelectionFinalTotalPrice($product, $selection, 0, $qty); + ->getSelectionFinalTotalPrice($product, $selection, 0, 1); $attributes = [ 'price' => $price, 'qty' => $qty, diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml index 508b9015f29ed..3ce33dab15d84 100644 --- a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminOrderActionGroup.xml @@ -123,6 +123,35 @@ <fillField selector="{{AdminOrderFormConfigureProductSection.quantity}}" userInput="{{quantity}}" stepKey="fillQuantity"/> <click selector="{{AdminOrderFormConfigureProductSection.ok}}" stepKey="clickOkConfigurablePopover"/> </actionGroup> + <!--Add bundle product to order --> + <actionGroup name="addBundleProductToOrder"> + <arguments> + <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"/> + <scrollTo selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" x="0" y="-100" stepKey="scrollToCheckColumn"/> + <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectBundleProduct"/> + <waitForElementVisible selector="{{AdminOrderFormBundleProductSection.quantity}}" stepKey="waitForBundleOptionLoad"/> + <wait time="2" stepKey="waitForOptionsToLoad"/> + <fillField selector="{{AdminOrderFormBundleProductSection.quantity}}" userInput="{{quantity}}" stepKey="fillQuantity"/> + <click selector="{{AdminOrderFormConfigureProductSection.ok}}" stepKey="clickOk"/> + <scrollTo selector="{{AdminOrderFormItemsSection.addSelected}}" x="0" y="-100" stepKey="scrollToAddSelectedButton"/> + <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> + </actionGroup> + <!--Add bundle product to order and check product price in the grid--> + <actionGroup name="addBundleProductToOrderAndCheckPriceInGrid" extends="addBundleProductToOrder"> + <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> + <actualResult type="variable">grabProductPriceFromGrid</actualResult> + </assertEquals> + </actionGroup> <!--Fill customer billing address--> <actionGroup name="fillOrderCustomerInformation"> <arguments> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBundleProductSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBundleProductSection.xml new file mode 100644 index 0000000000000..44a488204f775 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormBundleProductSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormBundleProductSection"> + <element name="quantity" type="input" selector="#product_composite_configure_input_qty"/> + <element name="ok" type="button" selector=".modal-header .page-actions button[data-role='action']" timeout="30"/> + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml index c4cf5bd05bb6f..1e4ea3b91a687 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminOrderFormItemsSection.xml @@ -14,6 +14,7 @@ <element name="skuFilter" type="input" selector="#sales_order_create_search_grid_filter_sku"/> <element name="rowCheck" type="checkbox" selector="#sales_order_create_search_grid_table > tbody tr:nth-of-type({{row}}) td.col-select [type=checkbox]" parameterized="true"/> <element name="rowQty" type="input" selector="#sales_order_create_search_grid_table > tbody tr:nth-of-type({{row}}) td.col-qty [name='qty']" parameterized="true"/> + <element name="rowPrice" type="text" selector="#sales_order_create_search_grid_table > tbody tr:nth-of-type({{row}}) td.price" parameterized="true"/> <element name="addSelected" type="button" selector="#order-search .admin__page-section-title .actions button.action-add" timeout="30"/> <element name="configure" type="button" selector=".product-configure-block button.action-default.scalable" timeout="30"/> <element name="selectProduct" type="checkbox" selector="//td[contains(text(), '{{arg}}')]/following-sibling::td[contains(@class, 'col-select col-in_products')]" parameterized="true"/> diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithBundleProductTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithBundleProductTest.xml new file mode 100644 index 0000000000000..d9529e5ee0b8a --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminCreateOrderWithBundleProductTest.xml @@ -0,0 +1,111 @@ +<?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="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminCreateOrderWithBundleProductTest"> + <annotations> + <title value="Create Order in Admin and update bundle product configuration"/> + <stories value="MAGETWO-96394: Wrong price calculation for bundle product on creating order from the admin panel"/> + <description value="Add bundle product with bundle option items with default quantity 2 to order in Admin and check price in product grid"/> + <features value="Sales"/> + <severity value="AVERAGE"/> + <group value="Sales"/> + </annotations> + + <before> + <!--Set default flat rate shipping method settings--> + <createData entity="FlatRateShippingMethodDefault" stepKey="setDefaultFlatRateShippingMethod"/> + + <!--Create simple customer--> + <createData entity="Simple_US_CA_Customer" stepKey="simpleCustomer"/> + + <!--Create simple product 1--> + <createData entity="ApiProductWithDescription" stepKey="simple1" before="simple2"/> + + <!--Create simple product 2--> + <createData entity="ApiProductWithDescription" stepKey="simple2" before="product"/> + + <!--Create bundle product with checkbox bundle option--> + <createData entity="ApiBundleProduct" stepKey="product"/> + <createData entity="CheckboxOption" stepKey="checkboxBundleOption"> + <requiredEntity createDataKey="product"/> + </createData> + + <!--Link simple product 1 to bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink1"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="checkboxBundleOption"/> + <requiredEntity createDataKey="simple1"/> + <field key="qty">2</field> + <field key="is_default">1</field> + </createData> + + <!--Link simple product 2 to bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink2"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="checkboxBundleOption"/> + <requiredEntity createDataKey="simple2"/> + <field key="qty">2</field> + <field key="is_default">1</field> + </createData> + + <!--Add drop-down bundle option--> + <createData entity="DropDownBundleOption" stepKey="dropDownBundleOption"> + <requiredEntity createDataKey="product"/> + </createData> + + <!--Link simple product 1 to drop-down bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink3"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="dropDownBundleOption"/> + <requiredEntity createDataKey="simple1"/> + <field key="qty">2</field> + <field key="is_default">1</field> + </createData> + + <!--Link simple product 2 to drop-down bundle option with default quantity 2--> + <createData entity="ApiBundleLink" stepKey="createBundleLink4"> + <requiredEntity createDataKey="product"/> + <requiredEntity createDataKey="dropDownBundleOption"/> + <requiredEntity createDataKey="simple2"/> + <field key="qty">2</field> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <!--Create new customer order--> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="navigateToNewOrderWithExistingCustomer"> + <argument name="customer" value="$$simpleCustomer$$"/> + </actionGroup> + + <!--Add bundle product to order and check product price in grid--> + <actionGroup ref="addBundleProductToOrderAndCheckPriceInGrid" stepKey="addBundleProductToOrder"> + <argument name="product" value="$$product$$"/> + <argument name="quantity" value="1"/> + <argument name="price" value="$738.00"/> + </actionGroup> + + <!--Select FlatRate shipping method--> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="orderSelectFlatRateShippingMethod"/> + + <!--Submit order--> + <click selector="{{AdminOrderFormActionSection.submitOrder}}" stepKey="submitOrder"/> + + <!--Verify order information--> + <actionGroup ref="verifyCreatedOrderInformation" stepKey="verifyCreatedOrderInformation"/> + + <after> + <actionGroup ref="logout" stepKey="logout"/> + + <deleteData createDataKey="product" stepKey="delete"/> + <deleteData createDataKey="simpleCustomer" stepKey="deleteSimpleCustomer"/> + <deleteData createDataKey="simple1" stepKey="deleteSimple1" before="deleteSimple2"/> + <deleteData createDataKey="simple2" stepKey="deleteSimple2" before="delete"/> + </after> + </test> +</tests> From f55e9fcdeb7c90b3282d87832aa93f8218965d3d Mon Sep 17 00:00:00 2001 From: OlgaVasyltsun <olga.vasyltsun@transoftgroup.com> Date: Tue, 4 Dec 2018 15:49:58 +0200 Subject: [PATCH 59/88] MAGETWO-95653: Product positions are incorrect after import --- .../Model/Import/ProductTest.php | 38 ++++++------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php index 027f2558aaf00..04db3df6653a6 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ProductTest.php @@ -1290,18 +1290,14 @@ public function testProductPositionInCategory() */ public function testNewProductPositionInCategory() { - $categoryId = 333; - - $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Framework\Filesystem::class - ); + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); $directory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); $source = $this->objectManager->create( \Magento\ImportExport\Model\Import\Source\Csv::class, [ 'file' => __DIR__ . '/_files/product_to_import_with_category.csv', - 'directory' => $directory + 'directory' => $directory, ] ); $errors = $this->_model->setSource( @@ -1313,29 +1309,17 @@ public function testNewProductPositionInCategory() ] )->validateData(); - $this->assertTrue($errors->getErrorsCount() == 0); + $this->assertTrue($errors->getErrorsCount() === 0); $this->_model->importData(); - /** @var \Magento\Framework\App\ResourceConnection $resourceConnection */ - $resourceConnection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\App\ResourceConnection::class - ); - $categoryProductstableName = $resourceConnection->getTableName('catalog_category_product'); - $productEntitiesTableName = $resourceConnection->getTableName('catalog_product_entity'); - $select = $resourceConnection->getConnection() - ->select() - ->from(['category_products' => $categoryProductstableName]) - ->join( - ['product_entities' => $productEntitiesTableName], - 'product_entities.entity_id = category_products.product_id', - '' - ) - ->where('category_products.category_id = ?', $categoryId) - ->where('product_entities.sku = "simpleImported"'); - $importedItem = $resourceConnection->getConnection()->fetchRow($select); - $this->assertTrue(is_array($importedItem)); - $this->assertNotEmpty($importedItem); - $this->assertEquals(0, $importedItem['position']); + /** @var ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + /** @var ProductInterface $product */ + $product = $productRepository->get('simpleImported'); + $categoryLinks = $product->getExtensionAttributes('category_links')->getCategoryLinks(); + $position = $categoryLinks[0]->getPosition(); + + $this->assertEquals(0, $position); } /** From 6744ab60a57c3a82844f5a2e2a40233b7ff3b333 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 4 Dec 2018 17:19:29 +0200 Subject: [PATCH 60/88] MAGETWO-72953: After return "RMA" is complete in Admin, "remaining quantity" in customer account shows incorrect value --- .../AddProductToCartActionGroup.xml | 13 ++++- .../Section/StorefrontProductPageSection.xml | 2 +- .../Customer/Test/Mftf/Data/AddressData.xml | 1 + .../Mftf/Page/StorefrontCustomerOrderPage.xml | 14 ----- .../Page/StorefrontCustomerOrderViewPage.xml | 5 +- .../Page/StorefrontCustomerOrdersGridPage.xml | 14 +++++ .../StorefrontCustomerOrdersGridSection.xml | 13 +++++ .../ActionGroup/AdminInvoiceActionGroup.xml | 53 +++++++++++++++++++ .../Test/Mftf/Page/AdminInvoiceNewPage.xml | 2 + .../AdminInvoiceAddressInformationSection.xml | 17 ++++++ .../Mftf/Section/AdminInvoiceItemsSection.xml | 3 +- .../AdminInvoiceMainActionsSection.xml | 4 +- ...voiceOrderAndAccountInformationSection.xml | 16 ++++++ .../ActionGroup/AdminShipmentActionGroup.xml | 49 +++++++++++++++++ .../Test/Mftf/Page/AdminShipmentNewPage.xml | 2 + ...AdminShipmentAddressInformationSection.xml | 17 ++++++ .../Section/AdminShipmentItemsSection.xml | 3 +- .../AdminShipmentMainActionsSection.xml | 4 +- ...pmentOrderAndAccountInformationSection.xml | 16 ++++++ .../Section/StorefrontMessagesSection.xml | 12 +++++ 20 files changed, 235 insertions(+), 25 deletions(-) delete mode 100644 app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrdersGridPage.xml create mode 100644 app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrdersGridSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceAddressInformationSection.xml create mode 100644 app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceOrderAndAccountInformationSection.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml create mode 100644 app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentOrderAndAccountInformationSection.xml create mode 100644 app/code/Magento/Ui/Test/Mftf/Section/StorefrontMessagesSection.xml diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml index 7dafeff34a2ea..848e169041982 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AddProductToCartActionGroup.xml @@ -7,7 +7,7 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="AddSimpleProductToCart"> <arguments> <argument name="product" defaultValue="product"/> @@ -15,7 +15,8 @@ <amOnPage stepKey="navigateProductPage" url="/{{product.name}}.html"/> <click stepKey="addToCart" selector="{{StorefrontProductPageSection.addToCartBtn}}"/> <waitForElementVisible selector="{{StorefrontProductPageSection.successMsg}}" time="30" stepKey="waitForProductAdded"/> - </actionGroup>. + </actionGroup> + <!--Click Add to Cart button in storefront product page--> <actionGroup name="addToCartFromStorefrontProductPage"> <arguments> @@ -28,4 +29,12 @@ <waitForPageLoad stepKey="waitForPageLoad"/> <see selector="{{StorefrontMessagesSection.success}}" userInput="You added {{productName}} to your shopping cart." stepKey="seeAddToCartSuccessMessage"/> </actionGroup> + + <actionGroup name="StorefrontAddProductToCartQuantityActionGroup" extends="addToCartFromStorefrontProductPage"> + <arguments> + <argument name="quantity" type="string" defaultValue="1"/> + </arguments> + <waitForElementVisible selector="{{StorefrontProductPageSection.QtyInput}}" time="30" before="addToCart" stepKey="waitQuantityFieldVisible"/> + <fillField selector="{{StorefrontProductPageSection.QtyInput}}" userInput="{{quantity}}" after="waitQuantityFieldVisible" stepKey="fillQuantityField"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml index c960f8432e64d..326a876662a6f 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontProductPageSection.xml @@ -10,7 +10,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontProductPageSection"> <element name="QtyInput" type="button" selector="input.input-text.qty"/> - <element name="addToCartBtn" type="button" selector="button.action.tocart.primary"/> + <element name="addToCartBtn" type="button" selector="button.action.tocart.primary" timeout="30"/> <element name="successMsg" type="button" selector="div.message-success"/> <element name="addToWishlist" type="button" selector="a.action.towishlist" timeout="30"/> <element name="addToCartButtonTitleIsAdding" type="text" selector="//button/span[text()='Adding...']"/> diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index c8ba70c7f8b50..4eea31665fe69 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -85,6 +85,7 @@ <data key="state">New York</data> <data key="postcode">11001</data> <data key="country_id">US</data> + <data key="country">United States</data> <data key="default_billing">Yes</data> <data key="default_shipping">Yes</data> <requiredEntity type="region">RegionNY</requiredEntity> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderPage.xml deleted file mode 100644 index 4e2ff7e907aa2..0000000000000 --- a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderPage.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="StorefrontCustomerOrderPage" url="/sales/order/history/" area="storefront" module="Magento_Customer"> - <section name="StorefrontCustomerOrderViewSection" /> - </page> -</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderViewPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderViewPage.xml index 3ac90876a7acf..9cd6dc1e69e35 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderViewPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrderViewPage.xml @@ -7,8 +7,9 @@ --> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> <page name="StorefrontCustomerOrderViewPage" url="sales/order/view/order_id/{{var1}}" area="storefront" module="Magento_Customer" parameterized="true"> <section name="StorefrontCustomerOrderSection" /> + <section name="StorefrontCustomerOrderViewSection" /> </page> -</pages> \ No newline at end of file +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrdersGridPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrdersGridPage.xml new file mode 100644 index 0000000000000..effc07d00f408 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Page/StorefrontCustomerOrdersGridPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/PageObject.xsd"> + <page name="StorefrontCustomerOrdersGridPage" url="/sales/order/history/" area="storefront" module="Magento_Customer"> + <section name="StorefrontCustomerOrdersGridSection"/> + </page> +</pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrdersGridSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrdersGridSection.xml new file mode 100644 index 0000000000000..de3975fd82d01 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/StorefrontCustomerOrdersGridSection.xml @@ -0,0 +1,13 @@ +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontCustomerOrdersGridSection"> + <element name="viewOrderAction" type="text" selector="//*[@id='my-orders-table']//*[text()='{{orderId}}']/..//a[contains(@class, 'action view')]" parameterized="true"/> + <element name="orderStatus" type="text" selector="//*[@id='my-orders-table']//*[text()='{{orderId}}']/..//td[contains(@class,'status')]" parameterized="true"/> + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml new file mode 100644 index 0000000000000..977cf84905cb4 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminInvoiceActionGroup.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <!--Check customer information is correct in invoice--> + <actionGroup name="VerifyBasicInvoiceInformation"> + <arguments> + <argument name="customer"/> + <argument name="shippingAddress"/> + <argument name="billingAddress"/> + <argument name="customerGroup" defaultValue="GeneralCustomerGroup"/> + </arguments> + <see selector="{{AdminInvoiceOrderAndAccountInformationSection.customerName}}" userInput="{{customer.firstname}}" stepKey="seeCustomerName"/> + <see selector="{{AdminInvoiceOrderAndAccountInformationSection.customerEmail}}" userInput="{{customer.email}}" stepKey="seeCustomerEmail"/> + <see selector="{{AdminInvoiceOrderAndAccountInformationSection.customerGroup}}" userInput="{{customerGroup.code}}" stepKey="seeCustomerGroup"/> + + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.street[0]}}" stepKey="seeBillingAddressStreet"/> + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.city}}" stepKey="seeBillingAddressCity"/> + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.country}}" stepKey="seeBillingAddressCountry"/> + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.postcode}}" stepKey="seeBillingAddressPostcode"/> + + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.street[0]}}" stepKey="seeShippingAddressStreet"/> + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.city}}" stepKey="seeShippingAddressCity"/> + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.country}}" stepKey="seeShippingAddressCountry"/> + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.postcode}}" stepKey="seeShippingAddressPostcode"/> + </actionGroup> + + <!--Check that product is in invoice items--> + <actionGroup name="SeeProductInInvoiceItems"> + <arguments> + <argument name="product"/> + </arguments> + <seeElement selector="{{AdminInvoiceItemsSection.productColumn(product.name)}}" stepKey="seeProductInInvoiceItemsGrid"/> + </actionGroup> + + <actionGroup name="StartCreateInvoiceFromOrderPage"> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceAction"/> + <seeInCurrentUrl url="{{AdminInvoiceNewPage.url}}" stepKey="seeNewInvoiceUrl"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seeNewInvoicePageTitle"/> + </actionGroup> + + <actionGroup name="SubmitInvoice"> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPageInvoice"/> + <see selector="{{AdminMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml b/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml index cfd5c5794a2de..4d01371f1efc5 100644 --- a/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml +++ b/app/code/Magento/Sales/Test/Mftf/Page/AdminInvoiceNewPage.xml @@ -11,6 +11,8 @@ <page name="AdminInvoiceNewPage" url="/sales/order_invoice/new/order_id/" area="admin" module="Magento_Sales"> <section name="AdminInvoiceNewSection"/> <section name="AdminInvoiceMainActionsSection"/> + <section name="AdminInvoiceOrderAndAccountInformationSection"/> + <section name="AdminInvoiceAddressInformationSection"/> <section name="AdminInvoiceTotalSection"/> <section name="AdminInvoiceItemsSection"/> </page> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceAddressInformationSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceAddressInformationSection.xml new file mode 100644 index 0000000000000..a3fca029096ec --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceAddressInformationSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceAddressInformationSection"> + <element name="billingAddress" type="text" selector=".order-billing-address address"/> + <element name="billingAddressEdit" type="button" selector=".order-billing-address .actions a"/> + <element name="shippingAddress" type="text" selector=".order-shipping-address address"/> + <element name="shippingAddressEdit" type="button" selector=".order-shipping-address .actions a"/> + </section> +</sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml index dbae8042b6554..ea99cfe8a1d7d 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceItemsSection.xml @@ -7,10 +7,11 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminInvoiceItemsSection"> <element name="itemQty" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-qty .qty-table" parameterized="true"/> <element name="itemQtyToInvoice" type="input" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-qty-invoice .qty-input" parameterized="true"/> <element name="updateQty" type="button" selector=".order-invoice-tables tfoot button[data-ui-id='order-items-update-button']"/> + <element name="productColumn" type="text" selector="//*[contains(@class,'order-invoice-tables')]//td[@class = 'col-product']//div[contains(text(),'{{productName}}')]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml index c1a9718b29b1c..f2a230adda019 100644 --- a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceMainActionsSection.xml @@ -7,8 +7,8 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminInvoiceMainActionsSection"> - <element name="submitInvoice" type="button" selector=".action-default.scalable.save.submit-button.primary"/> + <element name="submitInvoice" type="button" selector=".action-default.scalable.save.submit-button.primary" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceOrderAndAccountInformationSection.xml b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceOrderAndAccountInformationSection.xml new file mode 100644 index 0000000000000..e549f27155309 --- /dev/null +++ b/app/code/Magento/Sales/Test/Mftf/Section/AdminInvoiceOrderAndAccountInformationSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceOrderAndAccountInformationSection"> + <element name="customerName" type="text" selector=".order-account-information table tr:first-of-type > td span"/> + <element name="customerEmail" type="text" selector=".order-account-information table tr:nth-of-type(2) > td a"/> + <element name="customerGroup" type="text" selector=".order-account-information table tr:nth-of-type(3) > td"/> + </section> +</sections> diff --git a/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml new file mode 100644 index 0000000000000..6d4fb84d4ca3d --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/ActionGroup/AdminShipmentActionGroup.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="VerifyBasicShipmentInformation"> + <arguments> + <argument name="customer"/> + <argument name="shippingAddress"/> + <argument name="billingAddress"/> + <argument name="customerGroup" defaultValue="GeneralCustomerGroup"/> + </arguments> + <see selector="{{AdminShipmentOrderAndAccountInformationSection.customerName}}" userInput="{{customer.firstname}}" stepKey="seeCustomerName"/> + <see selector="{{AdminShipmentOrderAndAccountInformationSection.customerEmail}}" userInput="{{customer.email}}" stepKey="seeCustomerEmail"/> + <see selector="{{AdminShipmentOrderAndAccountInformationSection.customerGroup}}" userInput="{{customerGroup.code}}" stepKey="seeCustomerGroup"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.street[0]}}" stepKey="seeBillingAddressStreet"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.city}}" stepKey="seeBillingAddressCity"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.country}}" stepKey="seeBillingAddressCountry"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.postcode}}" stepKey="seeBillingAddressPostcode"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.street[0]}}" stepKey="seeShippingAddressStreet"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.city}}" stepKey="seeShippingAddressCity"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.country}}" stepKey="seeShippingAddressCountry"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.postcode}}" stepKey="seeShippingAddressPostcode"/> + </actionGroup> + + <actionGroup name="SeeProductInShipmentItems"> + <arguments> + <argument name="product"/> + </arguments> + <seeElement selector="{{AdminShipmentItemsSection.productColumn(product.name)}}" stepKey="seeProductInShipmentItemsGrid"/> + </actionGroup> + + <actionGroup name="StartCreateShipmentFromOrderPage"> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction"/> + <seeInCurrentUrl url="{{AdminShipmentNewPage.url}}" stepKey="seeNewShipmentUrl"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Shipment" stepKey="seeNewShipmentPageTitle"/> + </actionGroup> + + <actionGroup name="SubmitShipment"> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment"/> + <seeInCurrentUrl url="{{AdminOrderDetailsPage.url}}" stepKey="seeViewOrderPageShipping"/> + <see selector="{{AdminMessagesSection.successMessage}}" userInput="The shipment has been created." stepKey="seeShipmentCreateSuccess"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml index d7b91f68d21a2..bd311d3390043 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Page/AdminShipmentNewPage.xml @@ -10,6 +10,8 @@ xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> <page name="AdminShipmentNewPage" url="order_shipment/new/order_id/" area="admin" module="Magento_Shipping"> <section name="AdminShipmentMainActionsSection"/> + <section name="AdminShipmentOrderAndAccountInformationSection"/> + <section name="AdminShipmentAddressInformationSection"/> <section name="AdminShipmentItemsSection"/> </page> </pages> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml new file mode 100644 index 0000000000000..39035868c4b65 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentAddressInformationSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminShipmentAddressInformationSection"> + <element name="billingAddress" type="text" selector=".order-billing-address address"/> + <element name="billingAddressEdit" type="button" selector=".order-billing-address .actions a"/> + <element name="shippingAddress" type="text" selector=".order-shipping-address address"/> + <element name="shippingAddressEdit" type="button" selector=".order-shipping-address .actions a"/> + </section> +</sections> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml index 740cae14f8bc5..55d26d729090c 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentItemsSection.xml @@ -7,9 +7,10 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminShipmentItemsSection"> <element name="itemQty" type="text" selector=".order-shipment-table tbody:nth-of-type({{var1}}) .col-ordered-qty .qty-table" parameterized="true"/> <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-qty input.qty-item" parameterized="true"/> + <element name="productColumn" type="text" selector="//*[contains(@class,'order-shipment-table')]//td[@class = 'col-product']//div[contains(text(),'{{productName}}')]" parameterized="true"/> </section> </sections> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.xml index d79748d1e20cc..a21c3229e3549 100644 --- a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.xml +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentMainActionsSection.xml @@ -7,8 +7,8 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminShipmentMainActionsSection"> - <element name="submitShipment" type="button" selector="button.action-default.save.submit-button"/> + <element name="submitShipment" type="button" selector="button.action-default.save.submit-button" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentOrderAndAccountInformationSection.xml b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentOrderAndAccountInformationSection.xml new file mode 100644 index 0000000000000..2a83995cf3bbc --- /dev/null +++ b/app/code/Magento/Shipping/Test/Mftf/Section/AdminShipmentOrderAndAccountInformationSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="AdminShipmentOrderAndAccountInformationSection"> + <element name="customerName" type="text" selector=".order-account-information table tr:first-of-type > td span"/> + <element name="customerEmail" type="text" selector=".order-account-information table tr:nth-of-type(2) > td a"/> + <element name="customerGroup" type="text" selector=".order-account-information table tr:nth-of-type(3) > td"/> + </section> +</sections> diff --git a/app/code/Magento/Ui/Test/Mftf/Section/StorefrontMessagesSection.xml b/app/code/Magento/Ui/Test/Mftf/Section/StorefrontMessagesSection.xml new file mode 100644 index 0000000000000..98ab0cfe8dbe6 --- /dev/null +++ b/app/code/Magento/Ui/Test/Mftf/Section/StorefrontMessagesSection.xml @@ -0,0 +1,12 @@ +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> + <section name="StorefrontMessagesSection"> + <element name="successMessage" type="text" selector=".message-success"/> + </section> +</sections> From 682317c891d6618fd3d697728d7d8beb73df2bb4 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Tue, 4 Dec 2018 17:20:35 +0200 Subject: [PATCH 61/88] MAGETWO-72953: After return "RMA" is complete in Admin, "remaining quantity" in customer account shows incorrect value Fix MFTF gitignore issues --- dev/tests/acceptance/.gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dev/tests/acceptance/.gitignore b/dev/tests/acceptance/.gitignore index 7e27d5178fc48..d9cbc1f67a8a3 100755 --- a/dev/tests/acceptance/.gitignore +++ b/dev/tests/acceptance/.gitignore @@ -6,5 +6,6 @@ tests/_output/* tests/functional.suite.yml tests/functional/Magento/FunctionalTest/_generated vendor/* -mftf.logm +mftf.log /utils/ +.credentials.example From 336af4abb246f78be3278190db95077576139780 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Tue, 4 Dec 2018 23:08:52 +0200 Subject: [PATCH 62/88] MAGETWO-74012: [Github] ImportExport - Sample Files in own Modules #6553 --- .../Controller/Adminhtml/Import/Download.php | 38 +++-- .../Model/Import/SampleFileProvider.php | 127 ++++++++++++++ .../Model/Import/SampleFileProviderTest.php | 155 ++++++++++++++++++ app/code/Magento/ImportExport/etc/di.xml | 12 ++ 4 files changed, 317 insertions(+), 15 deletions(-) create mode 100644 app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php create mode 100644 app/code/Magento/ImportExport/Test/Unit/Model/Import/SampleFileProviderTest.php diff --git a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Download.php b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Download.php index 33dbba8320051..8b16e232856cd 100644 --- a/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Download.php +++ b/app/code/Magento/ImportExport/Controller/Adminhtml/Import/Download.php @@ -5,9 +5,9 @@ */ namespace Magento\ImportExport\Controller\Adminhtml\Import; +use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Component\ComponentRegistrar; use Magento\ImportExport\Controller\Adminhtml\Import as ImportController; -use Magento\Framework\App\Filesystem\DirectoryList; /** * Download sample file controller @@ -36,6 +36,11 @@ class Download extends ImportController */ protected $fileFactory; + /** + * @var \Magento\ImportExport\Model\Import\SampleFileProvider + */ + private $sampleFileProvider; + /** * Constructor * @@ -44,46 +49,48 @@ class Download extends ImportController * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory * @param \Magento\Framework\Filesystem\Directory\ReadFactory $readFactory * @param ComponentRegistrar $componentRegistrar + * @param \Magento\ImportExport\Model\Import\SampleFileProvider|null $sampleFileProvider */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\App\Response\Http\FileFactory $fileFactory, \Magento\Framework\Controller\Result\RawFactory $resultRawFactory, \Magento\Framework\Filesystem\Directory\ReadFactory $readFactory, - \Magento\Framework\Component\ComponentRegistrar $componentRegistrar + \Magento\Framework\Component\ComponentRegistrar $componentRegistrar, + \Magento\ImportExport\Model\Import\SampleFileProvider $sampleFileProvider = null ) { - parent::__construct( - $context - ); + parent::__construct($context); $this->fileFactory = $fileFactory; $this->resultRawFactory = $resultRawFactory; $this->readFactory = $readFactory; $this->componentRegistrar = $componentRegistrar; + $this->sampleFileProvider = $sampleFileProvider + ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\ImportExport\Model\Import\SampleFileProvider::class); } /** * Download sample file action * - * @return \Magento\Framework\Controller\Result\Raw + * @return \Magento\Framework\Controller\Result\Raw|\Magento\Framework\Controller\Result\Redirect */ public function execute() { - $fileName = $this->getRequest()->getParam('filename') . '.csv'; - $moduleDir = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, self::SAMPLE_FILES_MODULE); - $fileAbsolutePath = $moduleDir . '/Files/Sample/' . $fileName; - $directoryRead = $this->readFactory->create($moduleDir); - $filePath = $directoryRead->getRelativePath($fileAbsolutePath); + $entityName = $this->getRequest()->getParam('filename'); - if (!$directoryRead->isFile($filePath)) { + try { + $fileContents = $this->sampleFileProvider->getFileContents($entityName); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $this->messageManager->addError(__('There is no sample file for this entity.')); $resultRedirect = $this->resultRedirectFactory->create(); $resultRedirect->setPath('*/import'); + return $resultRedirect; } - $fileSize = isset($directoryRead->stat($filePath)['size']) - ? $directoryRead->stat($filePath)['size'] : null; + $fileSize = $this->sampleFileProvider->getSize($entityName); + $fileName = $entityName . '.csv'; $this->fileFactory->create( $fileName, @@ -95,7 +102,8 @@ public function execute() /** @var \Magento\Framework\Controller\Result\Raw $resultRaw */ $resultRaw = $this->resultRawFactory->create(); - $resultRaw->setContents($directoryRead->readFile($filePath)); + $resultRaw->setContents($fileContents); + return $resultRaw; } } diff --git a/app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php b/app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php new file mode 100644 index 0000000000000..4019f6ba83e81 --- /dev/null +++ b/app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php @@ -0,0 +1,127 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\ImportExport\Model\Import; + +use Magento\Framework\Component\ComponentRegistrar; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Filesystem\Directory\ReadInterface; +use Magento\Framework\Filesystem\Directory\ReadFactory; + +/** + * Import sample file provider model. + * + * This class support only *.csv. + */ +class SampleFileProvider +{ + /** + * Associate an import entity to its module, e.g ['entity_name' => 'module_name'] + * + * @var array + */ + private $samples; + + /** + * @var ComponentRegistrar + */ + private $componentRegistrar; + + /** + * @var ReadFactory + */ + private $readFactory; + + /** + * @param ReadFactory $readFactory + * @param ComponentRegistrar $componentRegistrar + * @param array $samples + */ + public function __construct( + ReadFactory $readFactory, + ComponentRegistrar $componentRegistrar, + array $samples = [] + ) { + $this->readFactory = $readFactory; + $this->componentRegistrar = $componentRegistrar; + $this->samples = $samples; + } + + /** + * Returns the size for the given file associated to an import entity. + * + * @param string $entityName + * @return int|null + * @throws NoSuchEntityException + */ + public function getSize(string $entityName) + { + $directoryRead = $this->getDirectoryRead($entityName); + $filePath = $this->getPath($entityName); + $fileSize = $directoryRead->stat($filePath)['size'] ?? null; + + return $fileSize; + } + + /** + * Returns content for the given file associated to an import entity. + * + * @param string $entityName + * @return string + */ + public function getFileContents(string $entityName): string + { + $directoryRead = $this->getDirectoryRead($entityName); + $filePath = $this->getPath($entityName); + + return $directoryRead->readFile($filePath); + } + + /** + * @return string $entityName + * @throws NoSuchEntityException + */ + private function getPath(string $entityName): string + { + $directoryRead = $this->getDirectoryRead($entityName); + $fileAbsolutePath = 'Files/Sample/' . $entityName . '.csv'; + $filePath = $directoryRead->getRelativePath($fileAbsolutePath); + + if (!$directoryRead->isFile($filePath)) { + throw new NoSuchEntityException(__("There is no file: %file", ['file' => $filePath])); + } + + return $filePath; + } + + /** + * @param string $entityName + * @return ReadInterface + */ + private function getDirectoryRead(string $entityName): ReadInterface + { + $moduleName = $this->getModuleName($entityName); + $moduleDir = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); + $directoryRead = $this->readFactory->create($moduleDir); + + return $directoryRead; + } + + /** + * @param string $entityName + * @return string + * @throws NoSuchEntityException + */ + private function getModuleName(string $entityName): string + { + if (!isset($this->samples[$entityName])) { + throw new NoSuchEntityException(); + } + + return $this->samples[$entityName]; + } +} diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/Import/SampleFileProviderTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/Import/SampleFileProviderTest.php new file mode 100644 index 0000000000000..28ed10ac3c3b9 --- /dev/null +++ b/app/code/Magento/ImportExport/Test/Unit/Model/Import/SampleFileProviderTest.php @@ -0,0 +1,155 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\ImportExport\Test\Unit\Model\Import; + +use Magento\Framework\Filesystem\Directory\ReadFactory; +use Magento\Framework\Filesystem\Directory\ReadInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\ImportExport\Model\Import\SampleFileProvider; + +/** + * Test class for Magento\ImportExport\Model\Import\SampleFileProvider. + */ +class SampleFileProviderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ReadInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $readerMock; + + /** + * @var ReadFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $readerFactoryMock; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var SampleFileProvider + */ + private $model; + + /** + * @var string + */ + private $entityName = 'test_sample'; + + /** + * @var string + */ + private $moduleName = 'Test_Sample'; + + /** + * @var string + */ + private $filePath = 'Files/Sample/test_sample.csv'; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->readerMock = $this->getMockBuilder(ReadInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->readerFactoryMock = $this->createMock(ReadFactory::class); + $this->readerFactoryMock->expects($this->any())->method('create')->willReturn($this->readerMock); + $this->readerMock->expects($this->any())->method('getRelativePath')->willReturnArgument(0); + $this->model = $this->objectManager->getObject( + SampleFileProvider::class, + [ + 'readFactory' => $this->readerFactoryMock, + ] + ); + } + + /** + * @return void + */ + public function testGetSize() + { + $fileSize = 10; + + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'samples', + [$this->entityName => $this->moduleName] + ); + $this->readerMock->expects($this->atLeastOnce())->method('isFile')->willReturn(true); + $this->readerMock->expects($this->once())->method('stat') + ->with($this->filePath) + ->willReturn(['size' => $fileSize]); + + $actualSize = $this->model->getSize($this->entityName); + $this->assertEquals($fileSize, $actualSize); + } + + /** + * @return void + */ + public function testGetFileContents() + { + $fileContent = 'test'; + + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'samples', + [$this->entityName => $this->moduleName] + ); + $this->readerMock->expects($this->atLeastOnce())->method('isFile')->willReturn(true); + $this->readerMock->expects($this->once())->method('readFile') + ->with($this->filePath) + ->willReturn($fileContent); + + $actualContent = $this->model->getFileContents($this->entityName); + $this->assertEquals($fileContent, $actualContent); + } + + /** + * @dataProvider methodDataProvider + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + * @param string $methodName + * @return void + */ + public function testMethodCallMissingSample(string $methodName) + { + $this->model->{$methodName}('missingType'); + } + + /** + * @dataProvider methodDataProvider + * @expectedException \Magento\Framework\Exception\NoSuchEntityException + * @expectedExceptionMessage There is no file: Files/Sample/test_sample.csv + * @param string $methodName + * @return void + */ + public function testMethodCallMissingFile(string $methodName) + { + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + 'samples', + [$this->entityName => $this->moduleName] + ); + $this->readerMock->expects($this->atLeastOnce())->method('isFile')->willReturn(false); + + $this->model->{$methodName}($this->entityName); + } + + /** + * @return array + */ + public function methodDataProvider(): array + { + return [ + ['getSize'], + ['getFileContents'], + ]; + } +} diff --git a/app/code/Magento/ImportExport/etc/di.xml b/app/code/Magento/ImportExport/etc/di.xml index 47acf7a356d93..36c76022a41c7 100644 --- a/app/code/Magento/ImportExport/etc/di.xml +++ b/app/code/Magento/ImportExport/etc/di.xml @@ -17,4 +17,16 @@ </argument> </arguments> </type> + <type name="Magento\ImportExport\Model\Import\SampleFileProvider"> + <arguments> + <argument name="samples" xsi:type="array"> + <item name="advanced_pricing" xsi:type="string">Magento_ImportExport</item> + <item name="catalog_product" xsi:type="string">Magento_ImportExport</item> + <item name="customer" xsi:type="string">Magento_ImportExport</item> + <item name="customer_address" xsi:type="string">Magento_ImportExport</item> + <item name="customer_composite" xsi:type="string">Magento_ImportExport</item> + <item name="customer_finance" xsi:type="string">Magento_ImportExport</item> + </argument> + </arguments> + </type> </config> From 7ce75fe6499128704dc7a955a3c69e556abf1a28 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Wed, 5 Dec 2018 09:37:44 +0200 Subject: [PATCH 63/88] MAGETWO-74012: [Github] ImportExport - Sample Files in own Modules #6553 --- .../ActionGroup/AdminProductAttributeActionGroup.xml | 6 ++++++ .../Test/StorefrontCheckingResultsOfFiltersTest.xml | 11 ++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml index dcc97fedbb8bf..91410a66e09b3 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeActionGroup.xml @@ -36,4 +36,10 @@ <click selector="{{AdminProductAttributeGridSection.attributeCode(attributeCode)}}" stepKey="clickRowToEdit"/> <waitForPageLoad stepKey="waitForColorAttributePageLoad"/> </actionGroup> + <!--Save product attribute and see success message--> + <actionGroup name="SaveProductAttribute"> + <scrollToTopOfPage stepKey="scrollToTop"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveAttribute"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the product attribute." stepKey="seeSuccessMessage"/> + </actionGroup> </actionGroups> diff --git a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml index 1d4a861ffe7b8..e6c3cb1788b31 100644 --- a/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml +++ b/app/code/Magento/LayeredNavigation/Test/Mftf/Test/StorefrontCheckingResultsOfFiltersTest.xml @@ -37,7 +37,7 @@ <click selector="{{AdminProductAttributeSetGridSection.deleteOptionByName('Black')}}" stepKey="deleteOption5"/> <!--Save attribute--> - <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveColorAttribute"/> + <actionGroup ref="SaveProductAttribute" stepKey="clickSaveColorAttribute"/> <!--Delete Category--> <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> @@ -87,7 +87,7 @@ <waitForElementVisible selector="{{AdminNewAttributePanelSection.isDefault('5')}}" time="30" stepKey="waitForOptionRow5"/> <fillField selector="{{AdminNewAttributePanelSection.optionAdminValue('4')}}" userInput="{{ColorProductAttribute5.name}}" stepKey="fillAdminLabel5"/> <!--Save attribute--> - <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveAttribute"/> + <actionGroup ref="SaveProductAttribute" stepKey="clickSaveAttribute"/> <!--Create 'material' attribute:--> <amOnPage url="{{ProductAttributePage.url}}" stepKey="goToNewProductAttributePage"/> @@ -122,9 +122,7 @@ <selectOption selector="{{AttributePropertiesSection.useInLayeredNavigation}}" userInput="1" stepKey="selectUseInLayeredNavigation"/> <!--Save attribute--> - <click selector="{{AdminNewAttributePanel.saveAttribute}}" stepKey="clickSaveNewAttribute"/> - <waitForPageLoad stepKey="waitForSavingNewAttribute"/> - <see userInput="You saved the product attribute." stepKey="seeSuccessMessage"/> + <actionGroup ref="SaveProductAttribute" stepKey="clickSaveNewAttribute"/> <click selector="{{AdminUserGridSection.resetButton}}" stepKey="clickResetButton"/> <!--Create attribute set--> @@ -204,8 +202,7 @@ <dragAndDrop selector1="{{AdminNewAttributePanelSection.attributeName('cotton')}}" selector2="{{AdminNewAttributePanelSection.attributeName('fabric')}}" stepKey="selectMaterialsSimple"/> <!-- Save the product --> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveSimpleProduct"/> - <see selector="{{AdminProductMessagesSection.successMessage}}" userInput="You saved the product." stepKey="assertSuccessSimpleProduct"/> + <actionGroup ref="saveProductForm" stepKey="saveSimpleProduct"/> <!--Clear caches--> <magentoCLI command="cache:flush" stepKey="flushCache"/> From 1a01f4ec48932c9dd3bdc3e7b0645902eff2196d Mon Sep 17 00:00:00 2001 From: Vasilii Burlacu <v.burlacu@atwix.com> Date: Tue, 27 Nov 2018 13:26:21 +0200 Subject: [PATCH 64/88] magento/magento2:#19418 Cannot add additional field to Newsletter system configuration at desired position - Adjusted Newsletter system configuration fields sortOrder so they has a step of 10 --- .../Newsletter/etc/adminhtml/system.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Newsletter/etc/adminhtml/system.xml b/app/code/Magento/Newsletter/etc/adminhtml/system.xml index 1173f64310304..277005240eabc 100644 --- a/app/code/Magento/Newsletter/etc/adminhtml/system.xml +++ b/app/code/Magento/Newsletter/etc/adminhtml/system.xml @@ -11,39 +11,39 @@ <label>Newsletter</label> <tab>customer</tab> <resource>Magento_Newsletter::newsletter</resource> - <group id="subscription" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1"> + <group id="subscription" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1"> <label>Subscription Options</label> - <field id="allow_guest_subscribe" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="allow_guest_subscribe" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Allow Guest Subscription</label> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> </field> - <field id="confirm" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="confirm" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Need to Confirm</label> <source_model>Magento\Config\Model\Config\Source\Yesno</source_model> </field> - <field id="confirm_email_identity" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="confirm_email_identity" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Confirmation Email Sender</label> <source_model>Magento\Config\Model\Config\Source\Email\Identity</source_model> </field> - <field id="confirm_email_template" translate="label comment" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="confirm_email_template" translate="label comment" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Confirmation Email Template</label> <comment>Email template chosen based on theme fallback when "Default" option is selected.</comment> <source_model>Magento\Config\Model\Config\Source\Email\Template</source_model> </field> - <field id="success_email_identity" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="success_email_identity" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Success Email Sender</label> <source_model>Magento\Config\Model\Config\Source\Email\Identity</source_model> </field> - <field id="success_email_template" translate="label comment" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="success_email_template" translate="label comment" type="select" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Success Email Template</label> <comment>Email template chosen based on theme fallback when "Default" option is selected.</comment> <source_model>Magento\Config\Model\Config\Source\Email\Template</source_model> </field> - <field id="un_email_identity" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="un_email_identity" translate="label" type="select" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Unsubscription Email Sender</label> <source_model>Magento\Config\Model\Config\Source\Email\Identity</source_model> </field> - <field id="un_email_template" translate="label comment" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> + <field id="un_email_template" translate="label comment" type="select" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1"> <label>Unsubscription Email Template</label> <comment>Email template chosen based on theme fallback when "Default" option is selected.</comment> <source_model>Magento\Config\Model\Config\Source\Email\Template</source_model> From ddff76c347bf40927011e840d10b14c26e59d7e6 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Wed, 5 Dec 2018 10:22:43 +0200 Subject: [PATCH 65/88] MAGETWO-96394: Wrong price calculation for bundle product on creating order from the admin panel --- app/code/Magento/Bundle/Model/Product/Type.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Bundle/Model/Product/Type.php b/app/code/Magento/Bundle/Model/Product/Type.php index a497597ee6fb1..fd024fa87109e 100644 --- a/app/code/Magento/Bundle/Model/Product/Type.php +++ b/app/code/Magento/Bundle/Model/Product/Type.php @@ -739,7 +739,7 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p * for selection (not for all bundle) */ $price = $product->getPriceModel() - ->getSelectionFinalTotalPrice($product, $selection, 0, 1); + ->getSelectionFinalTotalPrice($product, $selection, 0, $qty); $attributes = [ 'price' => $price, 'qty' => $qty, From 6077666f449c7644bb136dd8ea161746e9e67074 Mon Sep 17 00:00:00 2001 From: "rostyslav.hymon" <rostyslav.hymon@transoftgroup.com> Date: Wed, 5 Dec 2018 11:44:14 +0200 Subject: [PATCH 66/88] MAGETWO-94072: Configurable Product based on Swatch with different Admin & Front labels exported with wrong labels --- .../Model/Export/RowCustomizer.php | 27 +++++++++++++++++-- .../ConfigurableImportExport/composer.json | 3 ++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/ConfigurableImportExport/Model/Export/RowCustomizer.php b/app/code/Magento/ConfigurableImportExport/Model/Export/RowCustomizer.php index 58462b873d8b1..7146108f61fe1 100644 --- a/app/code/Magento/ConfigurableImportExport/Model/Export/RowCustomizer.php +++ b/app/code/Magento/ConfigurableImportExport/Model/Export/RowCustomizer.php @@ -3,14 +3,21 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\ConfigurableImportExport\Model\Export; -use Magento\CatalogImportExport\Model\Export\RowCustomizerInterface; use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection; -use Magento\ConfigurableProduct\Model\Product\Type\Configurable as ConfigurableProductType; +use Magento\CatalogImportExport\Model\Export\RowCustomizerInterface; use Magento\CatalogImportExport\Model\Import\Product as ImportProduct; +use Magento\ConfigurableProduct\Model\Product\Type\Configurable as ConfigurableProductType; use Magento\ImportExport\Model\Import; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; +/** + * Customizes output during export + */ class RowCustomizer implements RowCustomizerInterface { /** @@ -36,6 +43,19 @@ class RowCustomizer implements RowCustomizerInterface self::CONFIGURABLE_VARIATIONS_LABELS_COLUMN ]; + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @param StoreManagerInterface $storeManager + */ + public function __construct(StoreManagerInterface $storeManager) + { + $this->storeManager = $storeManager; + } + /** * Prepare configurable data for export * @@ -49,6 +69,9 @@ public function prepareData($collection, $productIds) $productCollection->addAttributeToFilter('entity_id', ['in' => $productIds]) ->addAttributeToFilter('type_id', ['eq' => ConfigurableProductType::TYPE_CODE]); + // set global scope during export + $this->storeManager->setCurrentStore(Store::DEFAULT_STORE_ID); + while ($product = $productCollection->fetchItem()) { $productAttributesOptions = $product->getTypeInstance()->getConfigurableOptions($product); $this->configurableData[$product->getId()] = []; diff --git a/app/code/Magento/ConfigurableImportExport/composer.json b/app/code/Magento/ConfigurableImportExport/composer.json index b2070fe7ebc44..2a51cb7486330 100644 --- a/app/code/Magento/ConfigurableImportExport/composer.json +++ b/app/code/Magento/ConfigurableImportExport/composer.json @@ -8,7 +8,8 @@ "magento/module-eav": "101.0.*", "magento/module-import-export": "100.2.*", "magento/module-configurable-product": "100.2.*", - "magento/framework": "101.0.*" + "magento/framework": "101.0.*", + "magento/module-store": "100.2.*" }, "type": "magento2-module", "version": "100.2.3", From d6f9b340793e7f4532ce65543b16d1f66b82b7b6 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Wed, 5 Dec 2018 11:50:59 +0200 Subject: [PATCH 67/88] MAGETWO-74012: [Github] ImportExport - Sample Files in own Modules #6553 --- .../Magento/ImportExport/Model/Import/SampleFileProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php b/app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php index 4019f6ba83e81..badffa6632174 100644 --- a/app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php +++ b/app/code/Magento/ImportExport/Model/Import/SampleFileProvider.php @@ -56,7 +56,6 @@ public function __construct( * * @param string $entityName * @return int|null - * @throws NoSuchEntityException */ public function getSize(string $entityName) { @@ -82,7 +81,8 @@ public function getFileContents(string $entityName): string } /** - * @return string $entityName + * @param string $entityName + * @return string * @throws NoSuchEntityException */ private function getPath(string $entityName): string From b5207df302cbde383b91521120c22ff8e3e89cdb Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Wed, 5 Dec 2018 13:53:55 +0200 Subject: [PATCH 68/88] MAGETWO-72953: After return "RMA" is complete in Admin, "remaining quantity" in customer account shows incorrect value --- .../StorefrontAddToCartCustomOptionsProductPageActionGroup.xml | 1 - .../StorefrontConfigurableProductWithFileCustomOptionTest.xml | 1 - .../Test/StorefrontSwatchProductWithFileCustomOptionTest.xml | 1 - 3 files changed, 3 deletions(-) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml index 4938b6a9592f1..91afd2eb5d4c7 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontAddToCartCustomOptionsProductPageActionGroup.xml @@ -13,7 +13,6 @@ <argument name="productName"/> </arguments> <click selector="{{StorefrontProductPageSection.addToCartBtn}}" stepKey="addToCart"/> - <waitForPageLoad stepKey="waitForPageLoad"/> <see selector="{{StorefrontProductPageSection.successMsg}}" userInput="You added {{productName}} to your shopping cart." stepKey="seeAddToCartSuccessMessage"/> </actionGroup> </actionGroups> diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml index a1e3e0b83e722..36615d3af6b7b 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductWithFileCustomOptionTest.xml @@ -60,7 +60,6 @@ <!--Try invalid file--> <attachFile selector="{{StorefrontProductInfoMainSection.addLinkFileUploadFile(ProductOptionFile.title)}}" userInput="lorem_ipsum.docx" stepKey="attachInvalidFile"/> <click selector="{{StorefrontProductPageSection.addToCartBtn}}" stepKey="addToCartInvalidFile"/> - <waitForPageLoad time="30" stepKey="waitForAddToCartWithError"/> <waitForElementVisible selector="{{StorefrontProductPageSection.alertMessage}}" stepKey="waitForErrorMessageInvalidFile"/> <see selector="{{StorefrontProductPageSection.messagesBlock}}" userInput="The file 'lorem_ipsum.docx' for '{{ProductOptionFile.title}}' has an invalid extension." stepKey="seeMessageInvalidFile"/> <!--Option remains selected--> diff --git a/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml b/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml index 1786b9bad236d..8f13860f75ad1 100644 --- a/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml +++ b/app/code/Magento/Swatches/Test/Mftf/Test/StorefrontSwatchProductWithFileCustomOptionTest.xml @@ -70,7 +70,6 @@ <!--Try invalid file--> <attachFile selector="{{StorefrontProductInfoMainSection.addLinkFileUploadFile(ProductOptionFile.title)}}" userInput="lorem_ipsum.docx" stepKey="attachInvalidFile"/> <click selector="{{StorefrontProductPageSection.addToCartBtn}}" stepKey="addToCartInvalidFile"/> - <waitForPageLoad time="30" stepKey="waitForAddToCartWithError"/> <waitForElementVisible selector="{{StorefrontProductPageSection.alertMessage}}" stepKey="waitForErrorMessageInvalidFile"/> <see selector="{{StorefrontProductPageSection.messagesBlock}}" userInput="The file 'lorem_ipsum.docx' for '{{ProductOptionFile.title}}' has an invalid extension." stepKey="seeMessageInvalidFile"/> <!--Swatch remains selected--> From f85f013a188d1be9674616a9cd8f9e27b73122f1 Mon Sep 17 00:00:00 2001 From: Myroslav Dobra <dmaraptor@gmail.com> Date: Wed, 5 Dec 2018 14:01:46 +0200 Subject: [PATCH 69/88] MAGETWO-72953: After return "RMA" is complete in Admin, "remaining quantity" in customer account shows incorrect value --- .../Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml index 379cb67d3e52f..3ad2c4cbdb6b1 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAvailabilityCreditMemoWithNoPaymentTest.xml @@ -77,7 +77,6 @@ <waitForPageLoad stepKey="waitForInvoicePageOpened"/> <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> - <waitForPageLoad stepKey="waitForInvoiceSaved"/> <see userInput="The invoice has been created." stepKey="seeCorrectMessage"/> <!--Verify that *Credit Memo* button is displayed--> From 876729d7b5afcd3943455458f62dca005b4b6d21 Mon Sep 17 00:00:00 2001 From: Serhii Voloshkov <serhii.voloshkov@transoftgroup.com> Date: Wed, 5 Dec 2018 14:13:12 +0200 Subject: [PATCH 70/88] MAGETWO-89487: Widget 'required field' error message is overlapped by the "Quick Search Form Types" field - styles fix --- app/design/adminhtml/Magento/backend/web/css/styles-old.less | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/design/adminhtml/Magento/backend/web/css/styles-old.less b/app/design/adminhtml/Magento/backend/web/css/styles-old.less index 6d46145df388c..319aad9770d69 100644 --- a/app/design/adminhtml/Magento/backend/web/css/styles-old.less +++ b/app/design/adminhtml/Magento/backend/web/css/styles-old.less @@ -4832,6 +4832,9 @@ margin-bottom: @indent__m; margin-top: -@indent__xl; } + select + .mage-error { + margin-top: 0; + } } } } From a42cd335442737fa29688264bd651cdc26e8ff59 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Wed, 5 Dec 2018 05:41:52 -0800 Subject: [PATCH 71/88] MAGETWO-95122: [Magento Cloud] Default value for category URL path does not save --- .../Model/CategoryUrlPathGenerator.php | 17 ++-- .../CategoryUrlPathAutogeneratorObserver.php | 57 +++++++++--- .../Model/CategoryUrlPathGeneratorTest.php | 55 ++++++++++++ ...tegoryUrlPathAutogeneratorObserverTest.php | 34 ++++++- .../Model/CategoryUrlRewriteGeneratorTest.php | 90 +++++++++++++++++++ 5 files changed, 233 insertions(+), 20 deletions(-) diff --git a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php index ee20b0e934b5d..2961dc4358970 100644 --- a/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php +++ b/app/code/Magento/CatalogUrlRewrite/Model/CategoryUrlPathGenerator.php @@ -8,6 +8,9 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Model\Category; +/** + * Class for generation category url_path. + */ class CategoryUrlPathGenerator { /** @@ -58,12 +61,13 @@ public function __construct( } /** - * Build category URL path + * Build category URL path. * * @param \Magento\Catalog\Api\Data\CategoryInterface|\Magento\Framework\Model\AbstractModel $category + * @param null|\Magento\Catalog\Api\Data\CategoryInterface|\Magento\Framework\Model\AbstractModel $parentCategory * @return string */ - public function getUrlPath($category) + public function getUrlPath($category, $parentCategory = null) { if (in_array($category->getParentId(), [Category::ROOT_CATEGORY_ID, Category::TREE_ROOT_ID])) { return ''; @@ -77,15 +81,18 @@ public function getUrlPath($category) return $category->getUrlPath(); } if ($this->isNeedToGenerateUrlPathForParent($category)) { - $parentPath = $this->getUrlPath( - $this->categoryRepository->get($category->getParentId(), $category->getStoreId()) - ); + $parentCategory = $parentCategory ?? + $this->categoryRepository->get($category->getParentId(), $category->getStoreId()); + $parentPath = $this->getUrlPath($parentCategory); $path = $parentPath === '' ? $path : $parentPath . '/' . $path; } + return $path; } /** + * Define whether we should generate URL path for parent. + * * @param \Magento\Catalog\Model\Category $category * @return bool */ diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php index eb54f0427c11a..74f688b665d8a 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/CategoryUrlPathAutogeneratorObserver.php @@ -13,6 +13,9 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Store\Model\Store; +/** + * Class observer to initiate generation category url_path. + */ class CategoryUrlPathAutogeneratorObserver implements ObserverInterface { /** @@ -46,6 +49,8 @@ public function __construct( } /** + * Generate Category Url Path. + * * @param \Magento\Framework\Event\Observer $observer * @return void * @throws \Magento\Framework\Exception\LocalizedException @@ -57,21 +62,39 @@ public function execute(\Magento\Framework\Event\Observer $observer) $useDefaultAttribute = !$category->isObjectNew() && !empty($category->getData('use_default')['url_key']); if ($category->getUrlKey() !== false && !$useDefaultAttribute) { $resultUrlKey = $this->categoryUrlPathGenerator->getUrlKey($category); - if (empty($resultUrlKey)) { - throw new \Magento\Framework\Exception\LocalizedException(__('Invalid URL key')); - } - $category->setUrlKey($resultUrlKey) - ->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); - if (!$category->isObjectNew()) { - $category->getResource()->saveAttribute($category, 'url_path'); - if ($category->dataHasChangedFor('url_path')) { - $this->updateUrlPathForChildren($category); - } + $this->updateUrlKey($category, $resultUrlKey); + } else if ($useDefaultAttribute) { + $resultUrlKey = $category->formatUrlKey($category->getOrigData('name')); + $this->updateUrlKey($category, $resultUrlKey); + $category->setUrlKey(null)->setUrlPath(null); + } + } + + /** + * Update Url Key. + * + * @param Category $category + * @param string $urlKey + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function updateUrlKey(Category $category, string $urlKey) + { + if (empty($urlKey)) { + throw new \Magento\Framework\Exception\LocalizedException(__('Invalid URL key')); + } + $category->setUrlKey($urlKey) + ->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); + if (!$category->isObjectNew()) { + $category->getResource()->saveAttribute($category, 'url_path'); + if ($category->dataHasChangedFor('url_path')) { + $this->updateUrlPathForChildren($category); } } } /** + * Update URL path for children. + * * @param Category $category * @return void */ @@ -94,8 +117,13 @@ protected function updateUrlPathForChildren(Category $category) } } else { foreach ($children as $child) { + /** @var Category $child */ $child->setStoreId($category->getStoreId()); - $this->updateUrlPathForCategory($child); + if ($child->getParentId() === $category->getId()) { + $this->updateUrlPathForCategory($child, $category); + } else { + $this->updateUrlPathForCategory($child); + } } } } @@ -112,13 +140,16 @@ protected function isGlobalScope($storeId) } /** + * Update URL path for category. + * * @param Category $category + * @param Category|null $parentCategory * @return void */ - protected function updateUrlPathForCategory(Category $category) + protected function updateUrlPathForCategory(Category $category, Category $parentCategory = null) { $category->unsUrlPath(); - $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category)); + $category->setUrlPath($this->categoryUrlPathGenerator->getUrlPath($category, $parentCategory)); $category->getResource()->saveAttribute($category, 'url_path'); } } diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php index 7297d150a8e6f..e804fb9d08e54 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/CategoryUrlPathGeneratorTest.php @@ -157,6 +157,61 @@ public function testGetUrlPathWithParent( $this->assertEquals($result, $this->categoryUrlPathGenerator->getUrlPath($this->category)); } + /** + * @return array + */ + public function getUrlPathWithParentCategoryDataProvider(): array + { + $requireGenerationLevel = CategoryUrlPathGenerator::MINIMAL_CATEGORY_LEVEL_FOR_PROCESSING; + $noGenerationLevel = CategoryUrlPathGenerator::MINIMAL_CATEGORY_LEVEL_FOR_PROCESSING - 1; + return [ + [13, 'url-key', false, $requireGenerationLevel, 10, 'parent-path', 'parent-path/url-key'], + [13, 'url-key', false, $requireGenerationLevel, Category::TREE_ROOT_ID, null, 'url-key'], + [13, 'url-key', true, $noGenerationLevel, Category::TREE_ROOT_ID, null, 'url-key'], + ]; + } + + /** + * Test receiving Url Path when parent category is presented. + * + * @param int $parentId + * @param string $urlKey + * @param bool $isCategoryNew + * @param bool $level + * @param int $parentCategoryParentId + * @param null|string $parentUrlPath + * @param string $result + * @dataProvider getUrlPathWithParentCategoryDataProvider + */ + public function testGetUrlPathWithParentCategory( + int $parentId, + string $urlKey, + bool $isCategoryNew, + bool $level, + int $parentCategoryParentId, + $parentUrlPath, + string $result + ) { + $urlPath = null; + $this->category->expects($this->any())->method('getParentId')->willReturn($parentId); + $this->category->expects($this->any())->method('getLevel')->willReturn($level); + $this->category->expects($this->any())->method('getUrlPath')->willReturn($urlPath); + $this->category->expects($this->any())->method('getUrlKey')->willReturn($urlKey); + $this->category->expects($this->any())->method('isObjectNew')->willReturn($isCategoryNew); + + $methods = ['getUrlPath', 'getParentId']; + $parentCategoryMock = $this->createPartialMock(\Magento\Catalog\Model\Category::class, $methods); + $parentCategoryMock->expects($this->any())->method('getParentId')->willReturn($parentCategoryParentId); + $parentCategoryMock->expects($this->any())->method('getUrlPath')->willReturn($parentUrlPath); + + $this->categoryRepository->expects($this->any()) + ->method('get') + ->with($parentCategoryParentId) + ->willReturn($parentCategoryMock); + + $this->assertEquals($result, $this->categoryUrlPathGenerator->getUrlPath($this->category, $parentCategoryMock)); + } + /** * @return array */ diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php index 1b4d1e08aa208..8ea5dc1ba621b 100644 --- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php +++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Observer/CategoryUrlPathAutogeneratorObserverTest.php @@ -49,7 +49,9 @@ protected function setUp() 'getResource', 'getUrlKey', 'getStoreId', - 'getData' + 'getData', + 'getOrigData', + 'formatUrlKey', ]); $this->category->expects($this->any())->method('getResource')->willReturn($this->categoryResource); $this->observer->expects($this->any())->method('getEvent')->willReturnSelf(); @@ -109,7 +111,35 @@ public function testExecuteWithException() $this->categoryUrlPathGenerator->expects($this->once()) ->method('getUrlKey') ->with($this->category) - ->willReturn(null); + ->willReturn(''); + $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); + } + + /** + * Test execute method when option use default url key is true. + */ + public function testExecuteWithUseDefault() + { + $categoryName = 'test'; + $categoryData = ['url_key' => 1]; + $this->category->expects($this->once())->method('getUrlKey')->willReturn($categoryName); + $this->category->expects($this->atLeastOnce()) + ->method('getData') + ->with('use_default') + ->willReturn($categoryData); + $this->category->expects($this->once())->method('getOrigData')->with('name')->willReturn('some_name'); + $this->category->expects($this->once())->method('formatUrlKey')->with('some_name')->willReturn('url_key'); + $this->category->expects($this->any())->method('setUrlKey') + ->willReturnMap([ + ['url_key', $this->category], + [null, $this->category], + ]); + $this->category->expects($this->any())->method('setUrlPath') + ->willReturnMap([ + ['url_path', $this->category], + [null, $this->category], + ]); + $this->categoryUrlPathAutogeneratorObserver->execute($this->observer); } diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php index a6cd7d195731c..747009818db69 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php @@ -14,6 +14,7 @@ /** * @magentoAppArea adminhtml + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CategoryUrlRewriteGeneratorTest extends \PHPUnit\Framework\TestCase { @@ -263,4 +264,93 @@ protected function assertResults($expected, $actual) ); } } + + /** + * Get all actual url paths. + * + * @param array $filter + * @return array + */ + private function getActualUrlPaths(array $filter) + { + /** @var \Magento\UrlRewrite\Model\UrlFinderInterface $urlFinder */ + $urlFinder = $this->objectManager->get(\Magento\UrlRewrite\Model\UrlFinderInterface::class); + $actualResults = []; + foreach ($urlFinder->findAllByData($filter) as $url) { + $actualResults[] = [ + $url->getRequestPath(), + $url->getTargetPath(), + $url->getStoreId(), + ]; + } + + return $actualResults; + } + + /** + * Test getting url path. + * + * @magentoDataFixture Magento/Store/_files/second_store.php + * @magentoDataFixture Magento/CatalogUrlRewrite/_files/categories.php + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testGetUrlPath() + { + /** @var \Magento\Catalog\Api\CategoryRepositoryInterface $repository */ + $repository = $this->objectManager->get(\Magento\Catalog\Api\CategoryRepositoryInterface::class); + + /** @var \Magento\Store\Api\StoreRepositoryInterface $storeRepository */ + $storeRepository = $this->objectManager->get(\Magento\Store\Api\StoreRepositoryInterface::class); + $storeId = $storeRepository->get('fixture_second_store')->getId(); + + $storeManager = $this->objectManager->get(\Magento\Store\Model\StoreManagerInterface::class); + $store = $storeManager->getStore($storeId); + $storeManager->setCurrentStore($store->getCode()); + + $categoryFilter = [ + UrlRewrite::ENTITY_TYPE => CategoryUrlRewriteGenerator::ENTITY_TYPE, + UrlRewrite::ENTITY_ID => [5], + ]; + + $category = $repository->get(5); + $category->addData( + [ + 'use_default' => [ + 'url_key' => 0, + ], + 'url_key_create_redirect' => 0, + 'url_key' => 'url-key', + ]); + $category->setStoreId($storeId); + $repository->save($category); + + $actualResults = $this->getActualUrlPaths($categoryFilter); + $categoryExpectedResult = [ + ['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 1], + ['category-1/category-1-1/url-key.html', 'catalog/category/view/id/5', 2], + ]; + + $this->assertResults($categoryExpectedResult, $actualResults); + + $category = $repository->get(5); + + $category->addData( + [ + 'use_default' => [ + 'url_key' => 1, + ], + 'url_key' => '', + ]); + + $repository->save($category); + + $actualResults = $this->getActualUrlPaths($categoryFilter); + $categoryExpectedResult = [ + ['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 1], + ['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 2], + ]; + + $this->assertResults($categoryExpectedResult, $actualResults); + } } From 8232358b43fa2d9bd18f18f696acc608f761a967 Mon Sep 17 00:00:00 2001 From: Serhiy Yelahin <serhiy.yelahin@transoftgroup.com> Date: Wed, 5 Dec 2018 17:15:11 +0200 Subject: [PATCH 72/88] MAGETWO-96174: [2.2] Improve order creation flow --- .../adminhtml/web/order/create/scripts.js | 131 ++++++++++++------ .../Test/Less/_files/blacklist/old.txt | 1 + 2 files changed, 86 insertions(+), 46 deletions(-) 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 05449c478152f..c508a5ecdfa58 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 @@ -14,7 +14,7 @@ define([ 'prototype', 'Magento_Catalog/catalog/product/composite/configure', 'Magento_Ui/js/lib/view/utils/async' -], function(jQuery, confirm, alert, template, shippingTemplate, paymentTemplate){ +], function (jQuery, confirm, alert, template, shippingTemplate, paymentTemplate) { window.AdminOrder = new Class.create(); @@ -42,7 +42,6 @@ define([ this.isOnlyVirtualProduct = false; this.excludedPaymentMethods = []; this.summarizePrice = true; - this.timerId = null; this.shippingTemplate = template(shippingTemplate, { data: { title: jQuery.mage.__('Shipping Method'), @@ -193,35 +192,42 @@ define([ } }, - isShippingField : function(fieldId){ - if(this.shippingAsBilling){ + /** + * Checks if the field belongs to the shipping address. + * + * @param {String} fieldId + * @return {Boolean} + */ + isShippingField: function (fieldId) { + if (this.shippingAsBilling) { return fieldId.include('billing'); } + return fieldId.include('shipping'); }, - isBillingField : function(fieldId){ + /** + * Checks if the field belongs to the billing address. + * + * @param {String} fieldId + * @return {Boolean} + */ + isBillingField: function (fieldId) { return fieldId.include('billing'); }, - bindAddressFields : function(container) { - var fields = $(container).select('input', 'select', 'textarea'); - for(var i=0;i<fields.length;i++){ - Event.observe(fields[i], 'change', this.triggerChangeEvent.bind(this)); - } - }, - /** - * Calls changing address field handler after timeout to prevent multiple simultaneous calls. + * Binds events on container form fields. * - * @param {Event} event + * @param {String} container */ - triggerChangeEvent: function (event) { - if (this.timerId) { - window.clearTimeout(this.timerId); - } + bindAddressFields: function (container) { + var fields = $(container).select('input', 'select', 'textarea'), + i; - this.timerId = window.setTimeout(this.changeAddressField.bind(this), 500, event); + for (i = 0; i < fields.length; i++) { + jQuery(fields[i]).change(this.changeAddressField.bind(this)); + } }, /** @@ -235,7 +241,8 @@ define([ matchRes = field.name.match(re), type, name, - data; + data, + resetShipping = false; if (!matchRes) { return; @@ -251,12 +258,21 @@ define([ } data = data.toObject(); - if (type === 'billing' && this.shippingAsBilling || type === 'shipping' && !this.shippingAsBilling) { + if (type === 'billing' && this.shippingAsBilling) { + this.syncAddressField(this.shippingAddressContainer, field.name, field.value); + resetShipping = true; + } + + if (type === 'shipping' && !this.shippingAsBilling) { + resetShipping = true; + } + + if (resetShipping) { data['reset_shipping'] = true; } data['order[' + type + '_address][customer_address_id]'] = null; - data['shipping_as_billing'] = +this.isShippingAsBilling(); + data['shipping_as_billing'] = +this.shippingAsBilling; if (name === 'customer_address_id') { data['order[' + type + '_address][customer_address_id]'] = @@ -264,8 +280,9 @@ define([ } this.resetPaymentMethod(); + if (data['reset_shipping']) { - this.resetShippingMethod(data); + this.resetShippingMethod(); } else { this.saveData(data); @@ -275,7 +292,28 @@ define([ } }, - fillAddressFields : function(container, data){ + /** + * Set address container form field value. + * + * @param {String} container - container ID + * @param {String} fieldName - form field name + * @param {*} fieldValue - form field value + */ + syncAddressField: function (container, fieldName, fieldValue) { + var syncName; + + if (this.isBillingField(fieldName)) { + syncName = fieldName.replace('billing', 'shipping'); + } + + $(container).select('[name="' + syncName + '"]').each(function (element) { + if (~['input', 'textarea', 'select'].indexOf(element.tagName.toLowerCase())) { + element.value = fieldValue; + } + }); + }, + + fillAddressFields: function(container, data){ var regionIdElem = false; var regionIdElemValue = false; @@ -316,10 +354,15 @@ define([ fields[i].setValue(data[name] ? data[name] : ''); } - if (fields[i].changeUpdater) fields[i].changeUpdater(); + if (fields[i].changeUpdater) { + fields[i].changeUpdater(); + } + if (name == 'region' && data['region_id'] && !data['region']){ fields[i].value = data['region_id']; } + + jQuery(fields[i]).trigger('change'); } }, @@ -350,16 +393,17 @@ define([ } }, - setShippingAsBilling : function(flag){ - var data; - var areasToLoad = ['billing_method', 'shipping_address', 'totals', 'giftmessage']; + /** + * Equals shipping and billing addresses. + * + * @param {Boolean} flag + */ + setShippingAsBilling: function (flag) { + var data, + areasToLoad = ['billing_method', 'shipping_address', 'shipping_method', 'totals', 'giftmessage']; + this.disableShippingAddress(flag); - if(flag){ - data = this.serializeData(this.billingAddressContainer); - } else { - data = this.serializeData(this.shippingAddressContainer); - } - areasToLoad.push('shipping_method'); + data = this.serializeData(flag ? this.billingAddressContainer : this.shippingAddressContainer); data = data.toObject(); data['shipping_as_billing'] = flag ? 1 : 0; data['reset_shipping'] = 1; @@ -367,21 +411,18 @@ define([ }, /** - * Checks if shipping address is corresponds to billing address. - * - * @return {Boolean} + * Replace shipping method area. */ - isShippingAsBilling: function () { - return jQuery('[name="shipping_same_as_billing"]').is(':checked'); - }, - - resetShippingMethod: function() { + resetShippingMethod: function () { if (!this.isOnlyVirtualProduct) { $(this.getAreaId('shipping_method')).update(this.shippingTemplate); } }, - resetPaymentMethod: function() { + /** + * Replace payment method area. + */ + resetPaymentMethod: function () { $(this.getAreaId('billing_method')).update(this.paymentTemplate); }, @@ -391,7 +432,7 @@ define([ * @return {Boolean} */ loadShippingRates: function () { - var addressContainer = this.isShippingAsBilling() ? + var addressContainer = this.shippingAsBilling ? 'billingAddressContainer' : 'shippingAddressContainer', data = this.serializeData(this[addressContainer]).toObject(); @@ -1505,6 +1546,4 @@ define([ return this._label; } }; - }); - diff --git a/dev/tests/static/testsuite/Magento/Test/Less/_files/blacklist/old.txt b/dev/tests/static/testsuite/Magento/Test/Less/_files/blacklist/old.txt index 70764344de69b..7e29ef51964bc 100644 --- a/dev/tests/static/testsuite/Magento/Test/Less/_files/blacklist/old.txt +++ b/dev/tests/static/testsuite/Magento/Test/Less/_files/blacklist/old.txt @@ -4,6 +4,7 @@ app/design/adminhtml/Magento/backend/Magento_ConfigurableProduct/web/css/source/ app/design/adminhtml/Magento/backend/Magento_Developer/web/css/source/_module-old.less app/design/adminhtml/Magento/backend/Magento_Enterprise/web/css/source/_module-old.less app/design/adminhtml/Magento/backend/Magento_Msrp/web/css/source/_module-old.less +app/design/adminhtml/Magento/backend/Magento_Sales/web/css/source/module/_order.less app/design/adminhtml/Magento/backend/Magento_Tax/web/css/source/_module-old.less app/design/adminhtml/Magento/backend/Magento_Theme/web/css/source/_module-old.less app/design/adminhtml/Magento/backend/Magento_Ui/web/css/source/_module-old.less From 50bdd367ca924e3b7bda1ab2d44fd3efcb095048 Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Thu, 6 Dec 2018 19:32:36 +0200 Subject: [PATCH 73/88] MAGETWO-96258: Discrepancy for sorting by a price of configurable products when Display Out of Stock Products enabled --- .../Product/Indexer/Price/Configurable.php | 46 +++++++- .../Indexer/Price/ConfigurableTest.php | 102 +++++++++++++----- 2 files changed, 118 insertions(+), 30 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php index 81e2e99bfe93a..b7bbf7aa1871c 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php @@ -12,6 +12,11 @@ use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\Query\BaseFinalPrice; use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructureFactory; use Magento\Catalog\Model\ResourceModel\Product\Indexer\Price\IndexTableStructure; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Store\Model\ScopeInterface; +use Magento\Framework\App\ObjectManager; +use Magento\CatalogInventory\Model\Stock; +use Magento\CatalogInventory\Model\Configuration; /** * Configurable Products Price Indexer Resource model @@ -65,6 +70,11 @@ class Configurable implements DimensionalIndexerInterface */ private $basePriceModifier; + /** + * @var ScopeConfigInterface + */ + private $scopeConfig; + /** * @param BaseFinalPrice $baseFinalPrice * @param IndexTableStructureFactory $indexTableStructureFactory @@ -74,6 +84,7 @@ class Configurable implements DimensionalIndexerInterface * @param BasePriceModifier $basePriceModifier * @param bool $fullReindexAction * @param string $connectionName + * @param ScopeConfigInterface $scopeConfig */ public function __construct( BaseFinalPrice $baseFinalPrice, @@ -83,7 +94,8 @@ public function __construct( \Magento\Framework\App\ResourceConnection $resource, BasePriceModifier $basePriceModifier, $fullReindexAction = false, - $connectionName = 'indexer' + $connectionName = 'indexer', + ScopeConfigInterface $scopeConfig = null ) { $this->baseFinalPrice = $baseFinalPrice; $this->indexTableStructureFactory = $indexTableStructureFactory; @@ -93,10 +105,11 @@ public function __construct( $this->resource = $resource; $this->fullReindexAction = $fullReindexAction; $this->basePriceModifier = $basePriceModifier; + $this->scopeConfig = $scopeConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class); } /** - * {@inheritdoc} + * @inheritdoc * * @throws \Exception */ @@ -184,7 +197,19 @@ private function fillTemporaryOptionsTable(string $temporaryOptionsTableName, ar ['le' => $this->getTable('catalog_product_entity')], 'le.' . $linkField . ' = l.parent_id', [] - )->columns( + ); + + // Does not make sense to extend query if out of stock products won't appear in tables for indexing + if ($this->isConfigShowOutOfStock()) { + $select->join( + ['si' => $this->getTable('cataloginventory_stock_item')], + 'si.product_id = l.product_id', + [] + ); + $select->where('si.is_in_stock = ?', Stock::STOCK_IN_STOCK); + } + + $select->columns( [ 'le.entity_id', 'customer_group_id', @@ -250,7 +275,7 @@ private function getMainTable($dimensions) /** * Get connection * - * return \Magento\Framework\DB\Adapter\AdapterInterface + * @return \Magento\Framework\DB\Adapter\AdapterInterface * @throws \DomainException */ private function getConnection(): \Magento\Framework\DB\Adapter\AdapterInterface @@ -272,4 +297,17 @@ private function getTable($tableName) { return $this->resource->getTableName($tableName, $this->connectionName); } + + /** + * Is flag Show Out Of Stock setted + * + * @return bool + */ + private function isConfigShowOutOfStock(): bool + { + return $this->scopeConfig->isSetFlag( + Configuration::XML_PATH_SHOW_OUT_OF_STOCK, + ScopeInterface::SCOPE_STORE + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php index 66091c108f0b2..5ec5fcfcb9c55 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php @@ -12,11 +12,18 @@ use Magento\Store\Model\Store; use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; +use Magento\CatalogInventory\Model\Stock; +use Magento\CatalogInventory\Api\StockItemRepositoryInterface; +use PHPUnit\Framework\TestCase; +use Magento\Catalog\Api\Data\ProductInterface; /** + * Configurable test + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @magentoAppArea adminhtml */ -class ConfigurableTest extends \PHPUnit\Framework\TestCase +class ConfigurableTest extends TestCase { /** * @var StoreManagerInterface @@ -28,26 +35,36 @@ class ConfigurableTest extends \PHPUnit\Framework\TestCase */ private $productRepository; + /** + * @var StockItemRepositoryInterface + */ + private $stockRepository; + + /** + * @inheritdoc + */ protected function setUp() { $this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class); $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class); + $this->stockRepository = Bootstrap::getObjectManager()->get(StockItemRepositoryInterface::class); } /** + * Test get product final price if one of child is disabled + * * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php * @magentoDbIsolation disabled + * + * @return void + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\StateException */ public function testGetProductFinalPriceIfOneOfChildIsDisabled() { - /** @var Collection $collection */ - $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) - ->create(); - $configurableProduct = $collection - ->addIdFilter([1]) - ->addMinimalPrice() - ->load() - ->getFirstItem(); + $configurableProduct = $this->getConfigurableProductFromCollection(); $this->assertEquals(10, $configurableProduct->getMinimalPrice()); $childProduct = $this->productRepository->getById(10, false, null, true); @@ -58,31 +75,25 @@ public function testGetProductFinalPriceIfOneOfChildIsDisabled() $this->productRepository->save($childProduct); $this->storeManager->setCurrentStore($currentStoreId); - /** @var Collection $collection */ - $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) - ->create(); - $configurableProduct = $collection - ->addIdFilter([1]) - ->addMinimalPrice() - ->load() - ->getFirstItem(); + $configurableProduct = $this->getConfigurableProductFromCollection(); $this->assertEquals(20, $configurableProduct->getMinimalPrice()); } /** + * Test get product final price if one of child is disabled per store + * * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php * @magentoDbIsolation disabled + * + * @return void + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\InputException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\StateException */ public function testGetProductFinalPriceIfOneOfChildIsDisabledPerStore() { - /** @var Collection $collection */ - $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) - ->create(); - $configurableProduct = $collection - ->addIdFilter([1]) - ->addMinimalPrice() - ->load() - ->getFirstItem(); + $configurableProduct = $this->getConfigurableProductFromCollection(); $this->assertEquals(10, $configurableProduct->getMinimalPrice()); $childProduct = $this->productRepository->getById(10, false, null, true); @@ -95,14 +106,53 @@ public function testGetProductFinalPriceIfOneOfChildIsDisabledPerStore() $this->productRepository->save($childProduct); $this->storeManager->setCurrentStore($currentStoreId); + $configurableProduct = $this->getConfigurableProductFromCollection(); + $this->assertEquals(20, $configurableProduct->getMinimalPrice()); + } + + /** + * Test get product minimal price if one child is out of stock + * + * @magentoConfigFixture current_store cataloginventory/options/show_out_of_stock 1 + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @magentoDbIsolation disabled + * + * @return void + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testGetProductMinimalPriceIfOneOfChildIsOutOfStock() + { + $configurableProduct = $this->getConfigurableProductFromCollection(); + $this->assertEquals(10, $configurableProduct->getMinimalPrice()); + + $childProduct = $this->productRepository->getById(10, false, null, true); + $stockItem = $childProduct->getExtensionAttributes()->getStockItem(); + $stockItem->setIsInStock(Stock::STOCK_OUT_OF_STOCK); + $this->stockRepository->save($stockItem); + + $configurableProduct = $this->getConfigurableProductFromCollection(); + $this->assertEquals(20, $configurableProduct->getMinimalPrice()); + } + + /** + * Retrieve configurable product. + * Returns Configurable product that was created by Magento/ConfigurableProduct/_files/product_configurable.php + * fixture + * + * @return ProductInterface + */ + private function getConfigurableProductFromCollection(): ProductInterface + { /** @var Collection $collection */ $collection = Bootstrap::getObjectManager()->get(CollectionFactory::class) ->create(); + /** @var ProductInterface $configurableProduct */ $configurableProduct = $collection ->addIdFilter([1]) ->addMinimalPrice() ->load() ->getFirstItem(); - $this->assertEquals(20, $configurableProduct->getMinimalPrice()); + + return $configurableProduct; } } From 2efa7b7d2df0275ed1918d5d4f12a82fe9b9dd47 Mon Sep 17 00:00:00 2001 From: Mastiuhin Olexandr <mastiuhin.olexandr@transoftgroup.com> Date: Fri, 7 Dec 2018 12:44:03 +0200 Subject: [PATCH 74/88] MAGETWO-96258: Discrepancy for sorting by a price of configurable products when Display Out of Stock Products enabled --- .../ResourceModel/Product/Indexer/Price/ConfigurableTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php index 5ec5fcfcb9c55..f02ab6acf7ac3 100644 --- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php +++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/ConfigurableTest.php @@ -125,7 +125,7 @@ public function testGetProductMinimalPriceIfOneOfChildIsOutOfStock() $configurableProduct = $this->getConfigurableProductFromCollection(); $this->assertEquals(10, $configurableProduct->getMinimalPrice()); - $childProduct = $this->productRepository->getById(10, false, null, true); + $childProduct = $this->productRepository->get('simple_10', false, null, true); $stockItem = $childProduct->getExtensionAttributes()->getStockItem(); $stockItem->setIsInStock(Stock::STOCK_OUT_OF_STOCK); $this->stockRepository->save($stockItem); From f441c4e5647fbf275a60fb1f169d6fcdb816f0f2 Mon Sep 17 00:00:00 2001 From: Daniel Ruf <daniel.ruf@ueberbit.de> Date: Tue, 27 Nov 2018 16:11:07 +0100 Subject: [PATCH 75/88] style: change b to strong (a11y) --- .../order/view/info/fraud_details.phtml | 4 ++-- .../view/adminhtml/email/failed_payment.html | 20 +++++++++---------- .../view/frontend/email/submitted_form.html | 8 ++++---- .../system/currency/rate/matrix.phtml | 4 ++-- .../templates/sample_email_content.phtml | 2 +- .../email/cron_error.html | 2 +- .../email/account_new_confirmed.html | 2 +- .../templates/sample_email_content.phtml | 2 +- .../sample_email_content_custom.phtml | 2 +- .../Magento_Customer/email/account_new.html | 2 +- .../email/account_new_confirmation.html | 2 +- lib/web/css/docs/forms.html | 2 +- lib/web/css/docs/variables.html | 2 +- setup/view/magento/setup/data-option.phtml | 4 ++-- setup/view/magento/setup/extension-grid.phtml | 4 ++-- setup/view/magento/setup/module-grid.phtml | 2 +- setup/view/magento/setup/select-version.phtml | 2 +- 17 files changed, 33 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/Authorizenet/view/adminhtml/templates/order/view/info/fraud_details.phtml b/app/code/Magento/Authorizenet/view/adminhtml/templates/order/view/info/fraud_details.phtml index 60fec263352fe..ac91fa30bfbe0 100644 --- a/app/code/Magento/Authorizenet/view/adminhtml/templates/order/view/info/fraud_details.phtml +++ b/app/code/Magento/Authorizenet/view/adminhtml/templates/order/view/info/fraud_details.phtml @@ -44,8 +44,8 @@ $fraudDetails = $payment->getAdditionalInformation('fraud_details'); <?php endif; ?> <?php if(!empty($fraudDetails['fraud_filters'])): ?> - <b><?= $block->escapeHtml(__('Fraud Filters')) ?>: - </b></br> + <strong><?= $block->escapeHtml(__('Fraud Filters')) ?>: + </strong></br> <?php foreach($fraudDetails['fraud_filters'] as $filter): ?> <?= $block->escapeHtml($filter['name']) ?>: <?= $block->escapeHtml($filter['action']) ?> diff --git a/app/code/Magento/Checkout/view/adminhtml/email/failed_payment.html b/app/code/Magento/Checkout/view/adminhtml/email/failed_payment.html index fb55f9b601dc9..03ad7d9e8d848 100644 --- a/app/code/Magento/Checkout/view/adminhtml/email/failed_payment.html +++ b/app/code/Magento/Checkout/view/adminhtml/email/failed_payment.html @@ -23,43 +23,43 @@ <h1>{{trans "Payment Transaction Failed"}}</h1> <ul> <li> - <b>{{trans "Reason"}}</b><br /> + <strong>{{trans "Reason"}}</strong><br /> {{var reason}} </li> <li> - <b>{{trans "Checkout Type"}}</b><br /> + <strong>{{trans "Checkout Type"}}</strong><br /> {{var checkoutType}} </li> <li> - <b>{{trans "Customer:"}}</b><br /> + <strong>{{trans "Customer:"}}</strong><br /> <a href="mailto:{{var customerEmail}}">{{var customer}}</a> <{{var customerEmail}}> </li> <li> - <b>{{trans "Items"}}</b><br /> + <strong>{{trans "Items"}}</strong><br /> {{var items|raw}} </li> <li> - <b>{{trans "Total:"}}</b><br /> + <strong>{{trans "Total:"}}</strong><br /> {{var total}} </li> <li> - <b>{{trans "Billing Address:"}}</b><br /> + <strong>{{trans "Billing Address:"}}</strong><br /> {{var billingAddress.format('html')|raw}} </li> <li> - <b>{{trans "Shipping Address:"}}</b><br /> + <strong>{{trans "Shipping Address:"}}</strong><br /> {{var shippingAddress.format('html')|raw}} </li> <li> - <b>{{trans "Shipping Method:"}}</b><br /> + <strong>{{trans "Shipping Method:"}}</strong><br /> {{var shippingMethod}} </li> <li> - <b>{{trans "Payment Method:"}}</b><br /> + <strong>{{trans "Payment Method:"}}</strong><br /> {{var paymentMethod}} </li> <li> - <b>{{trans "Date & Time:"}}</b><br /> + <strong>{{trans "Date & Time:"}}</strong><br /> {{var dateAndTime}} </li> </ul> diff --git a/app/code/Magento/Contact/view/frontend/email/submitted_form.html b/app/code/Magento/Contact/view/frontend/email/submitted_form.html index 1bce6159c586a..17146257aeff1 100644 --- a/app/code/Magento/Contact/view/frontend/email/submitted_form.html +++ b/app/code/Magento/Contact/view/frontend/email/submitted_form.html @@ -16,19 +16,19 @@ <table class="message-details"> <tr> - <td><b>{{trans "Name"}}</b></td> + <td><strong>{{trans "Name"}}</strong></td> <td>{{var data.name}}</td> </tr> <tr> - <td><b>{{trans "Email"}}</b></td> + <td><strong>{{trans "Email"}}</strong></td> <td>{{var data.email}}</td> </tr> <tr> - <td><b>{{trans "Phone"}}</b></td> + <td><strong>{{trans "Phone"}}</strong></td> <td>{{var data.telephone}}</td> </tr> </table> -<p><b>{{trans "Message"}}</b></p> +<p><strong>{{trans "Message"}}</strong></p> <p>{{var data.comment}}</p> {{template config_path="design/email/footer_template"}} diff --git a/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rate/matrix.phtml b/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rate/matrix.phtml index 8e0abcb319764..8a16eb71e0853 100644 --- a/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rate/matrix.phtml +++ b/app/code/Magento/CurrencySymbol/view/adminhtml/templates/system/currency/rate/matrix.phtml @@ -45,7 +45,7 @@ $_rates = ($_newRates) ? $_newRates : $_oldRates; class="admin__control-text" <?= ($_currencyCode == $_rate) ? ' disabled' : '' ?> /> <?php if (isset($_newRates) && $_currencyCode != $_rate && isset($_oldRates[$_currencyCode][$_rate])): ?> - <div class="admin__field-note"><?= /* @escapeNotVerified */ __('Old rate:') ?> <b><?= /* @escapeNotVerified */ $_oldRates[$_currencyCode][$_rate] ?></b></div> + <div class="admin__field-note"><?= /* @escapeNotVerified */ __('Old rate:') ?> <strong><?= /* @escapeNotVerified */ $_oldRates[$_currencyCode][$_rate] ?></strong></div> <?php endif; ?> </td> <?php else: ?> @@ -56,7 +56,7 @@ $_rates = ($_newRates) ? $_newRates : $_oldRates; class="admin__control-text" <?= ($_currencyCode == $_rate) ? ' disabled' : '' ?> /> <?php if (isset($_newRates) && $_currencyCode != $_rate && isset($_oldRates[$_currencyCode][$_rate])): ?> - <div class="admin__field-note"><?= /* @escapeNotVerified */ __('Old rate:') ?> <b><?= /* @escapeNotVerified */ $_oldRates[$_currencyCode][$_rate] ?></b></div> + <div class="admin__field-note"><?= /* @escapeNotVerified */ __('Old rate:') ?> <strong><?= /* @escapeNotVerified */ $_oldRates[$_currencyCode][$_rate] ?></strong></div> <?php endif; ?> </td> <?php endif; ?> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml index d53468a38376f..bb0073cedee96 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_Email/templates/sample_email_content.phtml @@ -4,4 +4,4 @@ * See COPYING.txt for license details. */ ?> -<b>Email content for adminhtml/Magento/default theme</b> +<strong>Email content for adminhtml/Magento/default theme</strong> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html index f13e54edf93a4..d65f9d4c40877 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/adminhtml/Magento/default/Magento_ProductAlert/email/cron_error.html @@ -4,4 +4,4 @@ * See COPYING.txt for license details. */ --> -<b>catalog_productalert_cron_error_email_template template from Magento/default</b> +<strong>catalog_productalert_cron_error_email_template template from Magento/default</strong> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html index f687fc041db1e..ffc4d8893fe98 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Customer/email/account_new_confirmed.html @@ -4,4 +4,4 @@ * See COPYING.txt for license details. */ --> -<b>customer_create_account_email_confirmed_template template from Magento/default</b> +<strong>customer_create_account_email_confirmed_template template from Magento/default</strong> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml index acbdf16d474df..9c973818272c8 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content.phtml @@ -4,4 +4,4 @@ * See COPYING.txt for license details. */ ?> -<b>Email content for frontend/Magento/default theme</b> +<strong>Email content for frontend/Magento/default theme</strong> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml index 1730bf904bb34..4ed5685ee0106 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Magento/default/Magento_Email/templates/sample_email_content_custom.phtml @@ -4,4 +4,4 @@ * See COPYING.txt for license details. */ ?> -<b>Custom Email content for frontend/Magento/default theme</b> +<strong>Custom Email content for frontend/Magento/default theme</strong> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html index 7e8f9bd1b12b6..46257060f8284 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/custom_theme/Magento_Customer/email/account_new.html @@ -4,4 +4,4 @@ * See COPYING.txt for license details. */ --> -<b>customer_create_account_email_template template from Vendor/custom_theme</b> +<strong>customer_create_account_email_template template from Vendor/custom_theme</strong> diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html index c5801b6557a61..9c52c5a1b38cf 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html +++ b/dev/tests/integration/testsuite/Magento/Email/Model/_files/design/frontend/Vendor/default/Magento_Customer/email/account_new_confirmation.html @@ -4,4 +4,4 @@ * See COPYING.txt for license details. */ --> -<b>customer_create_account_email_confirmation_template template from Vendor/default</b> +<strong>customer_create_account_email_confirmation_template template from Vendor/default</strong> diff --git a/lib/web/css/docs/forms.html b/lib/web/css/docs/forms.html index 211a9bd650ba0..dc08ddffd2066 100644 --- a/lib/web/css/docs/forms.html +++ b/lib/web/css/docs/forms.html @@ -713,7 +713,7 @@ <h2 id="simple-form-with-required-fields-message">Simple form with "require <th>@_type</th> <td class="vars_value">@form-element-input-type</td> <td class="vars_value">'' [input-text | select | textarea | input-radio | input-checkbox]</td> - <td>Form control type.<br/><b>@form-element-input__[]</b> global variables are used to set up all form elements style. Control-specific global variables use these <b>@form-element-input__[]</b> variables by default. Control-specific global variables can be set up separately.<br/><b>@input-text__[]</b> is used to set up input-text controls style<br/><b>@select__[]</b> is used to set up selects style<br/><b>@textarea__[]</b> is used to set up textarea style</td> + <td>Form control type.<br/><strong>@form-element-input__[]</strong> global variables are used to set up all form elements style. Control-specific global variables use these <strong>@form-element-input__[]</strong> variables by default. Control-specific global variables can be set up separately.<br/><strong>@input-text__[]</strong> is used to set up input-text controls style<br/><strong>@select__[]</strong> is used to set up selects style<br/><strong>@textarea__[]</strong> is used to set up textarea style</td> </tr> <tr> <th>@_background</th> diff --git a/lib/web/css/docs/variables.html b/lib/web/css/docs/variables.html index 4f353dc1554a4..ebbf2122ab209 100644 --- a/lib/web/css/docs/variables.html +++ b/lib/web/css/docs/variables.html @@ -3507,7 +3507,7 @@ <h4 id="the-codelibformelementinputcoed-mixin-variables">The <code>.lib-form-ele <th>@_type</th> <td class="vars_value">@form-element-input-type</td> <td class="vars_value">'' [input-text | select | textarea | input-radio | input-checkbox]</td> - <td>Form control type.<br/><b>@form-element-input__[]</b> global variables are used to set up all form elements style. Control-specific global variables use these <b>@form-element-input__[]</b> variables by default. Control-specific global variables can be set up separately.<br/><b>@input-text__[]</b> is used to set up input-text controls style<br/><b>@select__[]</b> is used to set up selects style<br/><b>@textarea__[]</b> is used to set up textarea style</td> + <td>Form control type.<br/><strong>@form-element-input__[]</strong> global variables are used to set up all form elements style. Control-specific global variables use these <strong>@form-element-input__[]</strong> variables by default. Control-specific global variables can be set up separately.<br/><strong>@input-text__[]</strong> is used to set up input-text controls style<br/><strong>@select__[]</strong> is used to set up selects style<br/><strong>@textarea__[]</strong> is used to set up textarea style</td> </tr> <tr> <th>@_background</th> diff --git a/setup/view/magento/setup/data-option.phtml b/setup/view/magento/setup/data-option.phtml index cb31d96013f24..656b04876c414 100644 --- a/setup/view/magento/setup/data-option.phtml +++ b/setup/view/magento/setup/data-option.phtml @@ -43,7 +43,7 @@ value="false" > <label class="form-label" for="keepData"> - <b>Keep data</b> + <strong>Keep data</strong> <br/><br/> Note: You can see the associated data in your database, however your customer will not see this in your online store. @@ -59,7 +59,7 @@ value="true" > <label class="form-label" for="removeData"> - <b>Remove data</b> + <strong>Remove data</strong> <br/><br/> Did you back up first? Choosing to remove data means the data is unavailable unless you recover it from a backup in the preceding step. diff --git a/setup/view/magento/setup/extension-grid.phtml b/setup/view/magento/setup/extension-grid.phtml index 47e5f7eec309b..df2203df2c054 100644 --- a/setup/view/magento/setup/extension-grid.phtml +++ b/setup/view/magento/setup/extension-grid.phtml @@ -66,8 +66,8 @@ <div class="row" ng-show="$root.isMarketplaceAuthorized && extensionsProcessed && total == 0"> <label class="form-label not-found"> - <b>You haven't purchased any extensions yet. Visit <a href="https://marketplace.magento.com">Marketplace</a> - for purchasing extensions.</b><br/> + <strong>You haven't purchased any extensions yet. Visit <a href="https://marketplace.magento.com">Marketplace</a> + for purchasing extensions.</strong><br/> </label> </div> <div class="admin__data-grid-outer-wrap" diff --git a/setup/view/magento/setup/module-grid.phtml b/setup/view/magento/setup/module-grid.phtml index 5fe0447b7c791..3bf9377104df1 100644 --- a/setup/view/magento/setup/module-grid.phtml +++ b/setup/view/magento/setup/module-grid.phtml @@ -8,7 +8,7 @@ <div class="row" ng-show="modulesProcessed && total == 0"> <label class="form-label"> - <b>We didn't find any modules at this time. Please try later.</b><br/> + <strong>We didn't find any modules at this time. Please try later.</strong><br/> </label> </div> <div class="admin__data-grid-outer-wrap" ng-show="modulesProcessed && total > 0"> diff --git a/setup/view/magento/setup/select-version.phtml b/setup/view/magento/setup/select-version.phtml index 920ab86252514..66264e46d50ad 100644 --- a/setup/view/magento/setup/select-version.phtml +++ b/setup/view/magento/setup/select-version.phtml @@ -128,7 +128,7 @@ </div> <div class="row" ng-show="componentsProcessed && total == 0"> <label class="form-label"> - <b>We didn't find any components to upgrade. Click "Next" to continue.<br/> + <strong>We didn't find any components to upgrade. Click "Next" to continue.</strong><br/> </label> </div> <div class="admin__data-grid-outer-wrap" ng-show="componentsProcessed && total > 0"> From 351340a2569f1a9deb93f8f9aa9afea728a1c59f Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Wed, 5 Dec 2018 13:15:28 +0200 Subject: [PATCH 76/88] Fix integration test. --- .../testsuite/Magento/Email/Model/Template/FilterTest.php | 8 ++++---- .../testsuite/Magento/Email/Model/TemplateTest.php | 8 ++++---- setup/view/magento/setup/extension-grid.phtml | 3 +++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/Template/FilterTest.php b/dev/tests/integration/testsuite/Magento/Email/Model/Template/FilterTest.php index a68b0942ec090..dd55dcc8b47c7 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/Template/FilterTest.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/Template/FilterTest.php @@ -130,22 +130,22 @@ public function layoutDirectiveDataProvider() 'area parameter - omitted' => [ 'adminhtml', 'handle="email_template_test_handle"', - '<b>Email content for frontend/Magento/default theme</b>', + '<strong>Email content for frontend/Magento/default theme</strong>', ], 'area parameter - frontend' => [ 'adminhtml', 'handle="email_template_test_handle" area="frontend"', - '<b>Email content for frontend/Magento/default theme</b>', + '<strong>Email content for frontend/Magento/default theme</strong>', ], 'area parameter - backend' => [ 'frontend', 'handle="email_template_test_handle" area="adminhtml"', - '<b>Email content for adminhtml/Magento/default theme</b>', + '<strong>Email content for adminhtml/Magento/default theme</strong>', ], 'custom parameter' => [ 'frontend', 'handle="email_template_test_handle" template="Magento_Email::sample_email_content_custom.phtml"', - '<b>Custom Email content for frontend/Magento/default theme</b>', + '<strong>Custom Email content for frontend/Magento/default theme</strong>', ], ]; return $result; diff --git a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php index a83de07443e95..7789a79794f39 100644 --- a/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php +++ b/dev/tests/integration/testsuite/Magento/Email/Model/TemplateTest.php @@ -315,25 +315,25 @@ public function templateDirectiveDataProvider() Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="customer/create_account/email_template"}}', - '<b>customer_create_account_email_template template from Vendor/custom_theme</b>', + '<strong>customer_create_account_email_template template from Vendor/custom_theme</strong>', ], 'Template from parent theme - frontend' => [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="customer/create_account/email_confirmation_template"}}', - '<b>customer_create_account_email_confirmation_template template from Vendor/default</b>', + '<strong>customer_create_account_email_confirmation_template template from Vendor/default</strong', ], 'Template from grandparent theme - frontend' => [ Area::AREA_FRONTEND, TemplateTypesInterface::TYPE_HTML, '{{template config_path="customer/create_account/email_confirmed_template"}}', - '<b>customer_create_account_email_confirmed_template template from Magento/default</b>', + '<strong>customer_create_account_email_confirmed_template template from Magento/default</strong', ], 'Template from grandparent theme - adminhtml' => [ BackendFrontNameResolver::AREA_CODE, TemplateTypesInterface::TYPE_HTML, '{{template config_path="catalog/productalert_cron/error_email_template"}}', - '<b>catalog_productalert_cron_error_email_template template from Magento/default</b>', + '<strong>catalog_productalert_cron_error_email_template template from Magento/default</strong', null, null, true, diff --git a/setup/view/magento/setup/extension-grid.phtml b/setup/view/magento/setup/extension-grid.phtml index df2203df2c054..4800d45e12d4f 100644 --- a/setup/view/magento/setup/extension-grid.phtml +++ b/setup/view/magento/setup/extension-grid.phtml @@ -3,6 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +// @codingStandardsIgnoreFile + ?> <h2 class="page-title">{{$state.current.header}}</h2> From b6bad10201751a30ad160bbc18d47febb1751b50 Mon Sep 17 00:00:00 2001 From: Daniel Ruf <daniel.ruf@ueberbit.de> Date: Wed, 28 Nov 2018 12:09:20 +0100 Subject: [PATCH 77/88] fix: remove unused params in categorySubmit invocation --- .../Magento/Catalog/view/adminhtml/web/catalog/category/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js index 75ee3019cf4b6..41f7a874c26f3 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/catalog/category/edit.js @@ -82,7 +82,7 @@ define([ return function (config, element) { config = config || {}; jQuery(element).on('click', function () { - categorySubmit(config.url, config.ajax); + categorySubmit(); }); }; }); From fc56b80ba8a0ebbc59054b29dc6ab13efdc76a29 Mon Sep 17 00:00:00 2001 From: Dmytro Cheshun <mitry@atwix.com> Date: Wed, 28 Nov 2018 11:23:38 +0200 Subject: [PATCH 78/88] Fix: SalesQuoteSaveAfterObserver fails to update the checkout session quote id when applicable #19424 --- .../Checkout/Observer/SalesQuoteSaveAfterObserver.php | 10 ++++++++-- .../Unit/Observer/SalesQuoteSaveAfterObserverTest.php | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Checkout/Observer/SalesQuoteSaveAfterObserver.php b/app/code/Magento/Checkout/Observer/SalesQuoteSaveAfterObserver.php index d926e33d54113..6bc7965ff5e34 100644 --- a/app/code/Magento/Checkout/Observer/SalesQuoteSaveAfterObserver.php +++ b/app/code/Magento/Checkout/Observer/SalesQuoteSaveAfterObserver.php @@ -7,6 +7,9 @@ use Magento\Framework\Event\ObserverInterface; +/** + * Class SalesQuoteSaveAfterObserver + */ class SalesQuoteSaveAfterObserver implements ObserverInterface { /** @@ -24,15 +27,18 @@ public function __construct(\Magento\Checkout\Model\Session $checkoutSession) } /** + * Assign quote to session + * * @param \Magento\Framework\Event\Observer $observer * @return void */ public function execute(\Magento\Framework\Event\Observer $observer) { + /* @var \Magento\Quote\Model\Quote $quote */ $quote = $observer->getEvent()->getQuote(); - /* @var $quote \Magento\Quote\Model\Quote */ + if ($quote->getIsCheckoutCart()) { - $this->checkoutSession->getQuoteId($quote->getId()); + $this->checkoutSession->setQuoteId($quote->getId()); } } } diff --git a/app/code/Magento/Checkout/Test/Unit/Observer/SalesQuoteSaveAfterObserverTest.php b/app/code/Magento/Checkout/Test/Unit/Observer/SalesQuoteSaveAfterObserverTest.php index 6070bb5d424c1..dabaf173d90b3 100644 --- a/app/code/Magento/Checkout/Test/Unit/Observer/SalesQuoteSaveAfterObserverTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Observer/SalesQuoteSaveAfterObserverTest.php @@ -30,13 +30,14 @@ protected function setUp() public function testSalesQuoteSaveAfter() { + $quoteId = 7; $observer = $this->createMock(\Magento\Framework\Event\Observer::class); $observer->expects($this->once())->method('getEvent')->will( $this->returnValue(new \Magento\Framework\DataObject( - ['quote' => new \Magento\Framework\DataObject(['is_checkout_cart' => 1, 'id' => 7])] + ['quote' => new \Magento\Framework\DataObject(['is_checkout_cart' => 1, 'id' => $quoteId])] )) ); - $this->checkoutSession->expects($this->once())->method('getQuoteId')->with(7); + $this->checkoutSession->expects($this->once())->method('setQuoteId')->with($quoteId); $this->object->execute($observer); } From 2e9d18793c67b78ceddc1886c6af069b83f17d9e Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 10 Dec 2018 11:08:03 +0200 Subject: [PATCH 79/88] MAGETWO-74012: [Github] ImportExport - Sample Files in own Modules #6553 --- .../Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml index 17f27056c555e..9817e24bed963 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminProductAttributeSetActionGroup.xml @@ -49,6 +49,7 @@ <arguments> <argument name="attributeSetName" type="string"/> </arguments> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> <click selector="{{AdminProductFormSection.attributeSet}}" stepKey="startEditAttrSet"/> <fillField selector="{{AdminProductFormSection.attributeSetFilter}}" userInput="{{attributeSetName}}" stepKey="searchForAttrSet"/> <waitForAjaxLoad stepKey="waitForLoad"/> From 1e18ab50ec06d0d81299d1a519184f1d3a57f41f Mon Sep 17 00:00:00 2001 From: DianaRusin <rusind95@gmail.com> Date: Mon, 10 Dec 2018 11:12:56 +0200 Subject: [PATCH 80/88] MAGETWO-89438: Advanced pricing the bulk discounts by percentage returns error when set --- .../AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml index 4f060bf40b4e3..8555615cc8781 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminValidateApplyingTierPriceWithEmptyDiscountValueTest.xml @@ -38,6 +38,7 @@ <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProductPage"> <argument name="product" value="$$createSimpleProduct$$"/> </actionGroup> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> <click selector="{{AdminProductFormSection.advancedPricingLink}}" stepKey="clickOnAdvancedPricingButton"/> <waitForElement selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="waitForCustomerGroupPriceAddButton"/> <click selector="{{AdminProductFormAdvancedPricingSection.customerGroupPriceAddButton}}" stepKey="addCustomerGroupPrice"/> From 7d93f369d60cb0b7a796499a5d9e53ac78222e16 Mon Sep 17 00:00:00 2001 From: Nikita Shcherbatykh <nikita.shcherbatykh@transoftgroup.com> Date: Mon, 10 Dec 2018 15:50:37 +0200 Subject: [PATCH 81/88] MAGETWO-96374: Product unassigned from category when store view order is changed --- .../Catalog/Model/ResourceModel/Category.php | 14 +- .../Model/ResourceModel/Category/Flat.php | 14 +- .../Controller/Adminhtml/CategoryTest.php | 156 ++++++++++++++++++ .../_files/products_in_different_stores.php | 122 ++++++++++++++ .../products_in_different_stores_rollback.php | 46 ++++++ 5 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores.php create mode 100644 dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores_rollback.php diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index 56b8a19d14255..737a30bed1fd6 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -484,8 +484,20 @@ public function getProductsPosition($category) $this->getCategoryProductTable(), ['product_id', 'position'] )->where( - 'category_id = :category_id' + 'catalog_category_product.category_id = ?', + $category->getId() ); + $websiteId = $category->getStore()->getWebsiteId(); + if ($websiteId) { + $select->join( + ['product_website' => $this->getTable('catalog_product_website')], + 'product_website.product_id = catalog_category_product.product_id', + [] + )->where( + 'product_website.website_id = ?', + $websiteId + ); + } $bind = ['category_id' => (int)$category->getId()]; return $this->getConnection()->fetchPairs($select, $bind); diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php index 9db2c8248ce52..2d3b7b742e494 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php @@ -699,8 +699,20 @@ public function getProductsPosition($category) $this->getTable('catalog_category_product'), ['product_id', 'position'] )->where( - 'category_id = :category_id' + 'catalog_category_product.category_id = ?', + $category->getId() ); + $websiteId = $category->getStore()->getWebsiteId(); + if ($websiteId) { + $select->join( + ['product_website' => $this->getTable('catalog_product_website')], + 'product_website.product_id = catalog_category_product.product_id', + [] + )->where( + 'product_website.website_id = ?', + $websiteId + ); + } $bind = ['category_id' => (int)$category->getId()]; return $this->getConnection()->fetchPairs($select, $bind); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php index bfc7e33d5f771..5f31f094625b6 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php @@ -5,11 +5,35 @@ */ namespace Magento\Catalog\Controller\Adminhtml; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Store\Model\Store; +use Magento\Catalog\Model\ResourceModel\Product; + /** * @magentoAppArea adminhtml */ class CategoryTest extends \Magento\TestFramework\TestCase\AbstractBackendController { + /** + * @var \Magento\Catalog\Model\ResourceModel\Product + */ + protected $productResource; + + /** + * @inheritDoc + * + * @throws \Magento\Framework\Exception\AuthenticationException + */ + protected function setUp() + { + parent::setUp(); + + /** @var Product $productResource */ + $this->productResource = Bootstrap::getObjectManager()->get( + Product::class + ); + } + /** * @magentoDataFixture Magento/Store/_files/core_fixturestore.php * @magentoDbIsolation enabled @@ -123,6 +147,9 @@ public static function categoryCreatedFromProductCreationPageDataProvider() return [[$postData], [$postData + ['return_session_messages_only' => 1]]]; } + /** + * Test SuggestCategories finds any categories. + */ public function testSuggestCategoriesActionDefaultCategoryFound() { $this->getRequest()->setParam('label_part', 'Default'); @@ -133,6 +160,9 @@ public function testSuggestCategoriesActionDefaultCategoryFound() ); } + /** + * Test SuggestCategories properly processes search by label. + */ public function testSuggestCategoriesActionNoSuggestions() { $this->getRequest()->setParam('label_part', strrev('Default')); @@ -322,6 +352,9 @@ public function saveActionDataProvider() ]; } + /** + * Test validation. + */ public function testSaveActionCategoryWithDangerRequest() { $this->getRequest()->setPostValue( @@ -393,4 +426,127 @@ public function moveActionDataProvider() [400, 401, 'first_url_key', 0, 'second_url_key', true], ]; } + + /** + * @magentoDataFixture Magento/Catalog/_files/products_in_different_stores.php + * @magentoDbIsolation disabled + * @dataProvider saveActionWithDifferentWebsitesDataProvider + * + * @param array $postData + */ + public function testSaveCategoryWithProductPosition(array $postData) + { + /** @var $store \Magento\Store\Model\Store */ + $store = Bootstrap::getObjectManager()->create(Store::class); + $store->load('fixturestore', 'code'); + $storeId = $store->getId(); + $oldCategoryProductsCount = $this->getCategoryProductsCount(); + $this->getRequest()->setParam('store', $storeId); + $this->getRequest()->setParam('id', 96377); + $this->getRequest()->setPostValue($postData); + $this->dispatch('backend/catalog/category/save'); + $newCategoryProductsCount = $this->getCategoryProductsCount(); + $this->assertEquals( + $oldCategoryProductsCount, + $newCategoryProductsCount, + 'After changing product position number of records from catalog_category_product has changed' + ); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @return array + */ + public function saveActionWithDifferentWebsitesDataProvider() + { + return [ + 'default_values' => [ + [ + 'store_id' => '1', + 'entity_id' => '96377', + 'attribute_set_id' => '4', + 'parent_id' => '2', + 'created_at' => '2018-11-29 08:28:37', + 'updated_at' => '2018-11-29 08:57:43', + 'path' => '1/2/96377', + 'level' => '2', + 'children_count' => '0', + 'row_id' => '96377', + 'name' => 'Category 1', + 'display_mode' => 'PRODUCTS', + 'url_key' => 'category-1', + 'url_path' => 'category-1', + 'automatic_sorting' => '0', + 'is_active' => '1', + 'is_anchor' => '1', + 'include_in_menu' => '1', + 'custom_use_parent_settings' => '0', + 'custom_apply_to_products' => '0', + 'path_ids' => [ + 0 => '1', + 1 => '2', + 2 => '96377' + ], + 'use_config' => [ + 'available_sort_by' => 'true', + 'default_sort_by' => 'true', + 'filter_price_range' => 'true' + ], + 'id' => '', + 'parent' => '0', + 'use_default' => [ + 'name' => '1', + 'url_key' => '1', + 'meta_title' => '1', + 'is_active' => '1', + 'include_in_menu' => '1', + 'custom_use_parent_settings' => '1', + 'custom_apply_to_products' => '1', + 'description' => '1', + 'landing_page' => '1', + 'display_mode' => '1', + 'custom_design' => '1', + 'page_layout' => '1', + 'meta_keywords' => '1', + 'meta_description' => '1', + 'custom_layout_update' => '1', + 'image' => '1' + ], + 'filter_price_range' => false, + 'meta_title' => false, + 'url_key_create_redirect' => 'category-1', + 'description' => false, + 'landing_page' => false, + 'default_sort_by' => 'position', + 'available_sort_by' => false, + 'custom_design' => false, + 'page_layout' => false, + 'meta_keywords' => false, + 'meta_description' => false, + 'custom_layout_update' => false, + 'position_cache_key' => '5c069248346ac', + 'is_smart_category' => '0', + 'smart_category_rules' => false, + 'sort_order' => '0', + 'vm_category_products' => '{"1":1,"3":0}' + ] + ] + ]; + } + + /** + * Get items count from catalog_category_product + * + * @return int + */ + private function getCategoryProductsCount(): int + { + $oldCategoryProducts = $this->productResource->getConnection()->select()->from( + $this->productResource->getTable('catalog_category_product'), + 'product_id' + ); + return count( + $this->productResource->getConnection()->fetchAll($oldCategoryProducts) + ); + } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores.php new file mode 100644 index 0000000000000..6102738bd6be4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\Indexer\IndexerRegistry; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Api\ProductRepositoryInterface; + +require __DIR__ . '/../../Store/_files/core_fixturestore.php'; + +$objectManager = Bootstrap::getObjectManager(); + +/** @var Magento\Store\Model\Website $website */ +$website = $objectManager->get(Magento\Store\Model\Website::class); + +$website->setData( + [ + 'code' => 'second_website', + 'name' => 'Test Website', + ] +); + +$website->save(); + +$objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->reinitStores(); + +/** @var IndexerRegistry $indexerRegistry */ +$indexerRegistry = $objectManager->create(IndexerRegistry::class); +$indexer = $indexerRegistry->get('catalogsearch_fulltext'); + +$indexer->reindexAll(); + +$category = $objectManager->create(\Magento\Catalog\Model\Category::class); +$category->isObjectNew(true); +$category->setId(96377) + ->setName('Category 1') + ->setParentId(2) + ->setPath('1/2/96377') + ->setLevel(2) + ->setAvailableSortBy('name') + ->setDefaultSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->save(); + +/** @var $product Product */ +$product = $objectManager->create(Product::class); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product') + ->setSku('simple_1') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with <b>html tag</b>') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setCategoryIds([96377]); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); + +/** @var $product Product */ +$product = $objectManager->create(Product::class); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([$website->getId()]) + ->setName('Simple Product 2') + ->setSku('simple_2') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with <b>html tag</b>') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setCategoryIds([96377]); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); + +/** @var $product Product */ +$product = $objectManager->create(Product::class); +$product->isObjectNew(true); +$product->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1, $website->getId()]) + ->setName('Simple Product 3') + ->setSku('simple_3') + ->setPrice(10) + ->setWeight(1) + ->setShortDescription("Short description") + ->setTaxClassId(0) + ->setDescription('Description with <b>html tag</b>') + ->setMetaTitle('meta title') + ->setMetaKeyword('meta keyword') + ->setMetaDescription('meta description') + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setCategoryIds([96377]); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$productRepository->save($product); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores_rollback.php new file mode 100644 index 0000000000000..9b957b75eb2a3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/products_in_different_stores_rollback.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +require __DIR__ . '/../../Store/_files/core_fixturestore_rollback.php'; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/** @var \Magento\Framework\Registry $registry */ +$registry = $objectManager->get(\Magento\Framework\Registry::class); + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); + +//Remove category +/** @var $category \Magento\Catalog\Model\Category */ +$category = $objectManager->create(\Magento\Catalog\Model\Category::class); +$category->load(96377); +if ($category->getId()) { + $category->delete(); +} + +$productSkuList = ['simple_1', 'simple_2', 'simple_3']; +foreach ($productSkuList as $sku) { + try { + $productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); + $product = $productRepository->get($sku, true); + if ($product->getId()) { + $productRepository->delete($product); + } + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + //Product already removed + } +} + +/** @var Magento\Store\Model\Website $website */ +$website = $objectManager->get(Magento\Store\Model\Website::class); +$website->load('second_website', 'code'); +if ($website->getId()) { + $website->delete(); +} + +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); From 204eb7c58bfeffb2357f7b5934475e34133a5e31 Mon Sep 17 00:00:00 2001 From: Stas Kozar <stas.kozar@transoftgroup.com> Date: Mon, 10 Dec 2018 16:55:00 +0200 Subject: [PATCH 82/88] MAGETWO-92576: Top menu should use cached version instead of rendering --- app/code/Magento/Theme/Block/Html/Topmenu.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Theme/Block/Html/Topmenu.php b/app/code/Magento/Theme/Block/Html/Topmenu.php index 2e643eadcf447..baf2f3878ad9b 100644 --- a/app/code/Magento/Theme/Block/Html/Topmenu.php +++ b/app/code/Magento/Theme/Block/Html/Topmenu.php @@ -78,6 +78,7 @@ protected function getCacheLifetime() * @param string $childrenWrapClass * @param int $limit * @return string + * @SuppressWarnings(PHPMD.RequestAwareBlockMethod) */ public function getHtml($outermostClass = '', $childrenWrapClass = '', $limit = 0) { From 810fcae9511901425677e2c2574b467bc24b70a0 Mon Sep 17 00:00:00 2001 From: Andrii Meysar <andrii.meysar@transoftgroup.com> Date: Mon, 10 Dec 2018 17:12:51 +0200 Subject: [PATCH 83/88] MAGETWO-72953: After return "RMA" is complete in Admin, "remaining quantity" in customer account shows incorrect value --- app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml index 37134657e62d6..4eea31665fe69 100644 --- a/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml +++ b/app/code/Magento/Customer/Test/Mftf/Data/AddressData.xml @@ -89,7 +89,6 @@ <data key="default_billing">Yes</data> <data key="default_shipping">Yes</data> <requiredEntity type="region">RegionNY</requiredEntity> - <data key="country">United States</data> </entity> <entity name="UK_Default_Address" type="address"> <data key="firstname">Jane</data> From 9987747ef19e90e745d02267cc597d25acea81a3 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <svitja@ukr.net> Date: Mon, 10 Dec 2018 23:20:39 -0800 Subject: [PATCH 84/88] MAGETWO-95122: [Magento Cloud] Default value for category URL path does not save --- .../Model/CategoryUrlRewriteGeneratorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php index 747009818db69..8dea5623a74c2 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/CategoryUrlRewriteGeneratorTest.php @@ -328,7 +328,7 @@ public function testGetUrlPath() $actualResults = $this->getActualUrlPaths($categoryFilter); $categoryExpectedResult = [ ['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 1], - ['category-1/category-1-1/url-key.html', 'catalog/category/view/id/5', 2], + ['category-1/category-1-1/url-key.html', 'catalog/category/view/id/5', $storeId], ]; $this->assertResults($categoryExpectedResult, $actualResults); @@ -348,7 +348,7 @@ public function testGetUrlPath() $actualResults = $this->getActualUrlPaths($categoryFilter); $categoryExpectedResult = [ ['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 1], - ['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', 2], + ['category-1/category-1-1/category-1-1-1.html', 'catalog/category/view/id/5', $storeId], ]; $this->assertResults($categoryExpectedResult, $actualResults); From 8078b7da6f9e652bbf7f9b9ef5b9efcc292ab135 Mon Sep 17 00:00:00 2001 From: serhii balko <serhii.balko@transoftgroup.com> Date: Tue, 11 Dec 2018 10:26:32 +0200 Subject: [PATCH 85/88] MAGETWO-96394: Wrong price calculation for bundle product on creating order from the admin panel --- .../Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 66a9709473623..1e69d30fa0ff6 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -69,6 +69,7 @@ <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced"/> <!--Change invoiced items count--> <fillField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="5" stepKey="invoiceHalfTheItems"/> + <waitForElementChange selector="{{AdminInvoiceItemsSection.updateQty}}" function="function($el) {return $el->isEnabled();}" stepKey="waitForUpdateQtyButtonEnabled"/> <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQtyToBeInvoiced"/> <waitForLoadingMaskToDisappear stepKey="waitForQtyToUpdate"/> <waitForElementVisible selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="waitforSubmitInvoiceBtn"/> From 5943774456f060bc8abcb247943e393d0aef528c Mon Sep 17 00:00:00 2001 From: serhii balko <serhii.balko@transoftgroup.com> Date: Wed, 12 Dec 2018 13:59:32 +0200 Subject: [PATCH 86/88] MAGETWO-94072: Configurable Product based on Swatch with different Admin & Front labels exported with wrong labels --- .../Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index 1e69d30fa0ff6..14c4ee7f2e6c1 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -69,7 +69,7 @@ <scrollTo selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" stepKey="scrollToItemsInvoiced"/> <!--Change invoiced items count--> <fillField selector="{{AdminInvoiceItemsSection.itemQtyToInvoice('1')}}" userInput="5" stepKey="invoiceHalfTheItems"/> - <waitForElementChange selector="{{AdminInvoiceItemsSection.updateQty}}" function="function($el) {return $el->isEnabled();}" stepKey="waitForUpdateQtyButtonEnabled"/> + <waitForElementChange selector="{{AdminInvoiceItemsSection.updateQty}}" function="function($el) {return $el->isEnabled();}" stepKey="waitForEnabledQtyToBeInvoicedSubmitButton"/> <click selector="{{AdminInvoiceItemsSection.updateQty}}" stepKey="updateQtyToBeInvoiced"/> <waitForLoadingMaskToDisappear stepKey="waitForQtyToUpdate"/> <waitForElementVisible selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="waitforSubmitInvoiceBtn"/> @@ -112,6 +112,7 @@ <!--Submit refund--> <scrollTo selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" stepKey="scrollToItemsToRefund"/> <fillField selector="{{AdminCreditMemoItemsSection.itemQtyToRefund('1')}}" userInput="5" after="scrollToItemsToRefund" stepKey="fillQtyOfItemsToRefund"/> + <waitForElementChange selector="{{AdminCreditMemoItemsSection.updateQty}}" function="function($el) {return $el->isEnabled();}" stepKey="waitForEnabledRefundQtySubmitButton"/> <click selector="{{AdminCreditMemoItemsSection.updateQty}}" stepKey="updateRefundQty"/> <waitForLoadingMaskToDisappear stepKey="waitForRefundQtyToUpdate"/> <waitForElementVisible selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="seeSubmitRefundBtn"/> From 022553fd81366abbeb6563aa64c63a20a4d020eb Mon Sep 17 00:00:00 2001 From: serhii balko <serhii.balko@transoftgroup.com> Date: Wed, 12 Dec 2018 17:43:10 +0200 Subject: [PATCH 87/88] MAGETWO-96374: Product unassigned from category when store view order is changed --- app/code/Magento/Catalog/Model/ResourceModel/Category.php | 4 ++-- .../Magento/Catalog/Model/ResourceModel/Category/Flat.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php index 737a30bed1fd6..7efcaed43cab2 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php @@ -484,14 +484,14 @@ public function getProductsPosition($category) $this->getCategoryProductTable(), ['product_id', 'position'] )->where( - 'catalog_category_product.category_id = ?', + "{$this->getTable('catalog_category_product')}.category_id = ?", $category->getId() ); $websiteId = $category->getStore()->getWebsiteId(); if ($websiteId) { $select->join( ['product_website' => $this->getTable('catalog_product_website')], - 'product_website.product_id = catalog_category_product.product_id', + "product_website.product_id = {$this->getTable('catalog_category_product')}.product_id", [] )->where( 'product_website.website_id = ?', diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php index 2d3b7b742e494..05950531e2178 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Flat.php @@ -699,14 +699,14 @@ public function getProductsPosition($category) $this->getTable('catalog_category_product'), ['product_id', 'position'] )->where( - 'catalog_category_product.category_id = ?', + "{$this->getTable('catalog_category_product')}.category_id = ?", $category->getId() ); $websiteId = $category->getStore()->getWebsiteId(); if ($websiteId) { $select->join( ['product_website' => $this->getTable('catalog_product_website')], - 'product_website.product_id = catalog_category_product.product_id', + "product_website.product_id = {$this->getTable('catalog_category_product')}.product_id", [] )->where( 'product_website.website_id = ?', From 1a7ef7ca1a3e986940a7371f71c0fdf340c3ce29 Mon Sep 17 00:00:00 2001 From: suryakant <suryakant.makwana@krishtechnolabs.com> Date: Sat, 8 Dec 2018 14:48:57 +0530 Subject: [PATCH 88/88] Fixed-icon-alignment: Sort by arrow icon alignment issue. --- .../Magento_Catalog/web/css/source/module/_toolbar.less | 5 +++++ .../luma/Magento_Catalog/web/css/source/module/_toolbar.less | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less index aceccb06d47f7..6abb291995e9f 100644 --- a/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/blank/Magento_Catalog/web/css/source/module/_toolbar.less @@ -62,6 +62,11 @@ .products.wrapper ~ .toolbar & { display: none; } + + .sorter-action { + position: relative; + top: -2px; + } } .sorter-options { diff --git a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less index 0997b9739125d..6bddc46003cbf 100644 --- a/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less +++ b/app/design/frontend/Magento/luma/Magento_Catalog/web/css/source/module/_toolbar.less @@ -38,7 +38,10 @@ .lib-css(box-shadow, @button__shadow); border-radius: 3px; } - + .sorter-action { + position: relative; + top: -2px; + } &-amount { left: 0; line-height: @toolbar-mode-icon-font-size + 2;