diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php index 00b093b2918f1..aa99918753e81 100644 --- a/app/code/Magento/Catalog/Model/Category.php +++ b/app/code/Magento/Catalog/Model/Category.php @@ -1130,10 +1130,15 @@ public function reindex() } } $productIndexer = $this->indexerRegistry->get(Indexer\Category\Product::INDEXER_ID); - if (!$productIndexer->isScheduled() - && (!empty($this->getAffectedProductIds()) || $this->dataHasChangedFor('is_anchor')) - ) { - $productIndexer->reindexList($this->getPathIds()); + + if (!empty($this->getAffectedProductIds()) + || $this->dataHasChangedFor('is_anchor') + || $this->dataHasChangedFor('is_active')) { + if (!$productIndexer->isScheduled()) { + $productIndexer->reindexList($this->getPathIds()); + } else { + $productIndexer->invalidate(); + } } } @@ -1165,16 +1170,14 @@ public function getIdentities() $identities[] = self::CACHE_TAG . '_' . $this->getId(); } - if ($this->hasDataChanges() || $this->isDeleted() || $this->dataHasChangedFor(self::KEY_INCLUDE_IN_MENU)) { - $identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $this->getId(); - } - + $identities = $this->getCategoryRelationIdentities($identities); + if ($this->isObjectNew()) { $identities[] = self::CACHE_TAG; } } - return $identities; + return array_unique($identities); } /** @@ -1460,5 +1463,25 @@ public function setExtensionAttributes(\Magento\Catalog\Api\Data\CategoryExtensi return $this->_setExtensionAttributes($extensionAttributes); } + /** + * Return category relation identities. + * + * @param array $identities + * @return array + */ + private function getCategoryRelationIdentities(array $identities): array + { + if ($this->hasDataChanges() || $this->isDeleted() || $this->dataHasChangedFor(self::KEY_INCLUDE_IN_MENU)) { + $identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $this->getId(); + if ($this->dataHasChangedFor('is_anchor') || $this->dataHasChangedFor('is_active')) { + foreach ($this->getPathIds() as $id) { + $identities[] = Product::CACHE_PRODUCT_CATEGORY_TAG . '_' . $id; + } + } + } + + return $identities; + } + //@codeCoverageIgnoreEnd } diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml index 2551bd61580ed..e46bfc7ee8b02 100644 --- a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml +++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/StorefrontCategoryActionGroup.xml @@ -19,6 +19,12 @@ + + + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductUpdateAttributesPage.xml b/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductUpdateAttributesPage.xml new file mode 100644 index 0000000000000..84996a3814571 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Page/AdminProductUpdateAttributesPage.xml @@ -0,0 +1,14 @@ + + + + +
+
+ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml index 6844006e4e399..8e13f9c38f805 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductFiltersSection.xml @@ -7,12 +7,13 @@ --> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductSEOSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductSEOSection.xml index 1d49d05363612..90c3856933be9 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductSEOSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductSEOSection.xml @@ -11,5 +11,6 @@
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection.xml new file mode 100644 index 0000000000000..051fda092d151 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminUpdateAttributesSection.xml @@ -0,0 +1,17 @@ + + + +
+ +
+
+ + +
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml index 1f1a4ce9133e7..3c769f9dbc0ce 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml @@ -22,5 +22,6 @@ +
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductAvailableAfterEnablingSubCategoriesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductAvailableAfterEnablingSubCategoriesTest.xml new file mode 100644 index 0000000000000..fe7858313c848 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductAvailableAfterEnablingSubCategoriesTest.xml @@ -0,0 +1,54 @@ + + + + + + + + + <description value="Check that parent categories are showing products after enabling subcategories"/> + <severity value="MAJOR"/> + <testCaseId value="MC-13914"/> + <useCaseId value="MAGETWO-96489"/> + <group value="Catalog"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SubCategoryWithParent" stepKey="createSubCategory"> + <requiredEntity createDataKey="createCategory"/> + <field key="is_active">false</field> + </createData> + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createSubCategory"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <!--Check anchor category is empty--> + <actionGroup ref="StorefrontCheckEmptyCategoryActionGroup" stepKey="checkEmptyAnchorCategory"> + <argument name="category" value="$$createCategory$$"/> + <argument name="productCount" value="0"/> + </actionGroup> + <!--Enable subcategory--> + <actionGroup ref="AdminNavigateToCategoryInTree" stepKey="openCreatedSubCategory"> + <argument name="category" value="$$createSubCategory$$"/> + </actionGroup> + <click selector="{{AdminCategoryBasicFieldSection.enableCategoryLabel}}" stepKey="enableCategory"/> + <actionGroup ref="saveCategoryForm" stepKey="saveCategory"/> + <!--Check created product in anchor category on storefront--> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="goToCategoryStorefront"/> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="seeCreatedProduct"> + <argument name="product" value="$$createSimpleProduct$$"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml index 68dbe628e9817..e7054839ef4d0 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest.xml @@ -7,7 +7,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"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> <test name="StorefrontPurchaseProductCustomOptionsDifferentStoreViewsTest"> <annotations> <features value="Purchase a product with Custom Options on different Store Views"/> @@ -16,9 +16,6 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-77831"/> <group value="product"/> - <skip> - <issueId value="MAGETWO-98182"/> - </skip> </annotations> <before> @@ -65,18 +62,23 @@ <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreView2"> <argument name="customStore" value="customStoreFR"/> </actionGroup> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearWebsitesGridFilters"/> + + <actionGroup ref="AdminOrdersGridClearFiltersActionGroup" stepKey="clearOrdersGridFilter"/> + + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearProductsGridFilters"/> </after> <!-- Open Product Grid, Filter product and open --> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> - <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="filterGroupedProductOptions"> <argument name="product" value="_defaultProduct"/> </actionGroup> - <click selector="{{AdminProductGridSection.productGridXRowYColumnButton('1', '2')}}" stepKey="openProductForEdit"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + <actionGroup ref="OpenEditProductOnBackendActionGroup" stepKey="openEditProductPage"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> <!-- Update Product with Option Value DropDown 1--> @@ -100,15 +102,12 @@ <!-- Switcher to Store FR--> - <scrollToTopOfPage stepKey="scrollToTopOfPage1"/> - - <click selector="{{AdminProductFormActionSection.changeStoreButton}}" stepKey="clickStoreSwitcher"/> - <click selector="{{AdminProductFormActionSection.selectStoreView(customStoreFR.name)}}" stepKey="clickStoreView"/> - <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="acceptMessage"/> + <actionGroup ref="AdminSwitchStoreViewActionGroup" stepKey="switchToStoreFR"> + <argument name="scopeName" value="customStoreFR.name"/> + </actionGroup> <!-- Open tab Customizable Options --> - <waitForPageLoad time="10" stepKey="waitForPageLoad4"/> <conditionalClick selector="{{AdminProductCustomizableOptionsSection.customizableOptions}}" dependentSelector="{{AdminProductCustomizableOptionsSection.checkIfCustomizableOptionsTabOpen}}" visible="true" stepKey="clickIfContentTabCloses3"/> <!-- Update Option Customizable Options and Option Value 1--> @@ -128,16 +127,13 @@ <!-- Login Customer Storefront --> - <amOnPage url="{{StorefrontCustomerSignInPage.url}}" stepKey="amOnSignInPage"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad6"/> - <fillField userInput="$$createCustomer.email$$" selector="{{StorefrontCustomerSignInFormSection.emailField}}" stepKey="fillEmail"/> - <fillField userInput="$$createCustomer.password$$" selector="{{StorefrontCustomerSignInFormSection.passwordField}}" stepKey="fillPassword"/> - <click selector="{{StorefrontCustomerSignInFormSection.signInAccountButton}}" stepKey="clickSignInAccountButton"/> + <actionGroup ref="CustomerLoginOnStorefront" stepKey="customerLogin"> + <argument name="customer" value="$$createCustomer$$" /> + </actionGroup> <!-- Go to Product Page --> <amOnPage url="{{StorefrontHomePage.url}}$$createProduct.custom_attributes[url_key]$$.html" stepKey="amOnProduct1Page"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad7"/> <seeElement selector="{{StorefrontProductInfoMainSection.productOptionDropDownTitle('Custom Options 1')}}" stepKey="seeProductOptionDropDownTitle"/> <seeElement selector="{{StorefrontProductInfoMainSection.productOptionDropDownOptionTitle('Custom Options 1', 'option1')}}" stepKey="seeproductOptionDropDownOptionTitle1"/> @@ -156,10 +152,7 @@ </actionGroup> <!-- Checking the correctness of displayed custom options for user parameters on checkout --> - - <click selector="{{StorefrontMiniCartSection.show}}" stepKey="clickCart"/> - <click selector="{{StorefrontMiniCartSection.goToCheckout}}" stepKey="goToCheckout"/> - <waitForPageLoad stepKey="s33"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart" /> <conditionalClick selector="{{CheckoutPaymentSection.cartItemsArea}}" dependentSelector="{{CheckoutPaymentSection.cartItemsArea}}" visible="true" stepKey="exposeMiniCart"/> @@ -177,23 +170,29 @@ <conditionalClick selector="{{CheckoutPaymentSection.productOptionsByProductItemPrice('150')}}" dependentSelector="{{CheckoutPaymentSection.productOptionsActiveByProductItemPrice('150')}}" visible="false" stepKey="exposeProductOptions1"/> <see selector="{{CheckoutPaymentSection.productOptionsActiveByProductItemPrice('150')}}" userInput="option2" stepKey="seeProductOptionValueDropdown1Input2"/> - <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad8"/> <!-- Place Order --> - <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder1"/> - <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <!--Select shipping method--> + <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectFlatRateShippingMethod"/> + <waitForElementVisible selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskAfterClickNext"/> + <!--Select payment method--> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod"/> + <!-- Place Order --> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="customerPlaceOrder"> + <argument name="orderNumberMessage" value="CONST.successCheckoutOrderNumberMessage"/> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage"/> + </actionGroup> <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="grabOrderNumber"/> <!-- Open Order --> - <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad9"/> - <fillField selector="{{OrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> - <click selector="{{OrdersGridSection.submitSearch}}" stepKey="submitSearch"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask4"/> + <actionGroup ref="filterOrderGridById" stepKey="openOrdersGrid"> + <argument name="orderId" value="{$grabOrderNumber}"/> + </actionGroup> <click selector="{{OrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> <waitForPageLoad time="30" stepKey="waitForPageLoad10"/> @@ -205,14 +204,12 @@ <!-- Switch to FR Store View Storefront --> <amOnPage url="{{StorefrontHomePage.url}}" stepKey="amOnProduct4Page"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad11"/> - <click selector="{{StorefrontHeaderSection.storeViewSwitcher}}" stepKey="clickStoreViewSwitcher1"/> - <waitForElementVisible selector="{{StorefrontHeaderSection.storeViewDropdown}}" stepKey="waitForStoreViewDropdown1"/> - <click selector="{{StorefrontHeaderSection.storeViewOption(customStoreFR.code)}}" stepKey="selectStoreView1"/> - <waitForPageLoad stepKey="waitForPageLoad12"/> - <amOnPage url="{{StorefrontHomePage.url}}$$createProduct.custom_attributes[url_key]$$.html" stepKey="amOnProduct2Page"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad13"/> + <actionGroup ref="StorefrontSwitchStoreViewActionGroup" stepKey="switchStore"> + <argument name="storeView" value="customStoreFR"/> + </actionGroup> + + <amOnPage url="{{StorefrontProductPage.url($$createProduct.custom_attributes[url_key]$$)}}" stepKey="amOnProduct2Page"/> <seeElement selector="{{StorefrontProductInfoMainSection.productOptionDropDownTitle('FR Custom Options 1')}}" stepKey="seeProductFrOptionDropDownTitle"/> <seeElement selector="{{StorefrontProductInfoMainSection.productOptionDropDownOptionTitle('FR Custom Options 1', 'FR option1')}}" stepKey="productFrOptionDropDownOptionTitle1"/> @@ -232,9 +229,7 @@ <!-- Checking the correctness of displayed custom options for user parameters on checkout --> - <click selector="{{StorefrontMiniCartSection.show}}" stepKey="clickCart1"/> - <click selector="{{StorefrontMiniCartSection.goToCheckout}}" stepKey="goToCheckout1"/> - <waitForPageLoad stepKey="s34"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart2" /> <conditionalClick selector="{{CheckoutPaymentSection.cartItemsArea}}" dependentSelector="{{CheckoutPaymentSection.cartItemsArea}}" visible="true" stepKey="exposeMiniCart1"/> @@ -252,18 +247,26 @@ <conditionalClick selector="{{CheckoutPaymentSection.productOptionsByProductItemPrice('150')}}" dependentSelector="{{CheckoutPaymentSection.productOptionsActiveByProductItemPrice('150')}}" visible="false" stepKey="exposeProductOptions3"/> <see selector="{{CheckoutPaymentSection.productOptionsActiveByProductItemPrice('150')}}" userInput="FR option2" stepKey="seeProductFrOptionValueDropdown1Input3"/> - <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext1"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad14"/> <!-- Place Order --> - <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder2"/> - <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder1"/> + <!--Select shipping method--> + <actionGroup ref="CheckoutSelectFlatRateShippingMethodActionGroup" stepKey="selectFlatRateShippingMethod2"/> + <waitForElementVisible selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton2"/> + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext2"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskAfterClickNext2"/> + + <!--Select payment method--> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod2"/> + <!-- Place Order --> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="customerPlaceOrder2"> + <argument name="orderNumberMessage" value="CONST.successCheckoutOrderNumberMessage"/> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage"/> + </actionGroup> <!-- Open Product Grid, Filter product and open --> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGridPage1"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad15"/> <actionGroup ref="SearchForProductOnBackendActionGroup" stepKey="filterGroupedProductOptions1"> <argument name="product" value="_defaultProduct"/> @@ -296,8 +299,7 @@ <!--Go to Product Page--> - <amOnPage url="{{StorefrontHomePage.url}}$$createProduct.custom_attributes[url_key]$$.html" stepKey="amOnProduct2Page2"/> - <waitForPageLoad time="30" stepKey="waitForPageLoad20"/> + <amOnPage url="{{StorefrontProductPage.url($$createProduct.custom_attributes[url_key]$$)}}" stepKey="amOnProduct2Page2"/> <seeElement selector="{{StorefrontProductInfoMainSection.productOptionDropDownTitle('Custom Options 1')}}" stepKey="seeProductOptionDropDownTitle1"/> <seeElement selector="{{StorefrontProductInfoMainSection.productOptionDropDownOptionTitle('Custom Options 1', 'option1')}}" stepKey="seeProductOptionDropDownOptionTitle3"/> diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php index a53b87dcf1567..c84753ad4adcb 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php @@ -348,13 +348,15 @@ public function testReindexFlatEnabled($flatScheduled, $productScheduled, $expec public function reindexFlatDisabledTestDataProvider() { return [ - [false, null, null, null, 0], - [true, null, null, null, 0], - [false, [], null, null, 0], - [false, ["1", "2"], null, null, 1], - [false, null, 1, null, 1], - [false, ["1", "2"], 0, 1, 1], - [false, null, 1, 1, 0], + [false, null, null, null, null, null, 0], + [true, null, null, null, null, null, 0], + [false, [], null, null, null, null, 0], + [false, ["1", "2"], null, null, null, null, 1], + [false, null, 1, null, null, null, 1], + [false, ["1", "2"], 0, 1, null, null, 1], + [false, null, 1, 1, null, null, 0], + [false, ["1", "2"], null, null, 0, 1, 1], + [false, ["1", "2"], null, null, 1, 0, 1], ]; } @@ -363,6 +365,8 @@ public function reindexFlatDisabledTestDataProvider() * @param array $affectedIds * @param int|string $isAnchorOrig * @param int|string $isAnchor + * @param mixed $isActiveOrig + * @param mixed $isActive, * @param int $expectedProductReindexCall * * @dataProvider reindexFlatDisabledTestDataProvider @@ -372,12 +376,16 @@ public function testReindexFlatDisabled( $affectedIds, $isAnchorOrig, $isAnchor, + $isActiveOrig, + $isActive, $expectedProductReindexCall ) { $this->category->setAffectedProductIds($affectedIds); $this->category->setData('is_anchor', $isAnchor); $this->category->setOrigData('is_anchor', $isAnchorOrig); $this->category->setAffectedProductIds($affectedIds); + $this->category->setData('is_active', $isActive); + $this->category->setOrigData('is_active', $isActiveOrig); $pathIds = ['path/1/2', 'path/2/3']; $this->category->setData('path_ids', $pathIds); @@ -387,7 +395,7 @@ public function testReindexFlatDisabled( ->method('isFlatEnabled') ->will($this->returnValue(false)); - $this->productIndexer->expects($this->exactly(1)) + $this->productIndexer->expects($this->any()) ->method('isScheduled') ->willReturn($productScheduled); $this->productIndexer->expects($this->exactly($expectedProductReindexCall)) diff --git a/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php b/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php index fc2056e83ec70..94798753ca63f 100644 --- a/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php +++ b/app/code/Magento/CatalogUrlRewrite/Observer/ProductToWebsiteChangeObserver.php @@ -14,6 +14,9 @@ use Magento\UrlRewrite\Model\UrlPersistInterface; use Magento\UrlRewrite\Service\V1\Data\UrlRewrite; +/** + * Observer to assign the products to website. + */ class ProductToWebsiteChangeObserver implements ObserverInterface { /** @@ -69,12 +72,14 @@ public function execute(\Magento\Framework\Event\Observer $observer) $this->request->getParam('store_id', Store::DEFAULT_STORE_ID) ); - $this->urlPersist->deleteByData([ - UrlRewrite::ENTITY_ID => $product->getId(), - UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, - ]); - if ($product->getVisibility() != Visibility::VISIBILITY_NOT_VISIBLE) { - $this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product)); + if (!empty($this->productUrlRewriteGenerator->generate($product))) { + $this->urlPersist->deleteByData([ + UrlRewrite::ENTITY_ID => $product->getId(), + UrlRewrite::ENTITY_TYPE => ProductUrlRewriteGenerator::ENTITY_TYPE, + ]); + if ($product->getVisibility() != Visibility::VISIBILITY_NOT_VISIBLE) { + $this->urlPersist->replace($this->productUrlRewriteGenerator->generate($product)); + } } } } diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminUrlForProductRewrittenCorrectlyTest.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminUrlForProductRewrittenCorrectlyTest.xml new file mode 100644 index 0000000000000..d52395342c092 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminUrlForProductRewrittenCorrectlyTest.xml @@ -0,0 +1,71 @@ +<?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="AdminUrlForProductRewrittenCorrectlyTest"> + <annotations> + <features value="CatalogUrlRewrite"/> + <stories value="Url rewrites for products"/> + <title value="Check that URL for product rewritten correctly"/> + <description value="Check that URL for product rewritten correctly"/> + <severity value="MAJOR"/> + <testCaseId value="MC-13913"/> + <useCaseId value="MAGETWO-73534"/> + <group value="catalog"/> + <group value="catalogUrlRewrite"/> + </annotations> + <before> + <!--Create product--> + <createData entity="_defaultCategory" stepKey="category"/> + <createData entity="ApiSimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="category"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <!--Delete created data--> + <deleteData createDataKey="createProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Open Created product--> + <amOnPage url="{{AdminProductEditPage.url($$createProduct.id$$)}}" stepKey="openProductEditPage"/> + <!--Switch to Default Store view--> + <actionGroup ref="SwitchToTheNewStoreView" stepKey="selectDefaultStoreView"> + <argument name="storeViewName" value="_defaultStore"/> + </actionGroup> + + <!--Set use default url--> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSearchEngineOptimizationTab"/> + <waitForElementVisible selector="{{AdminProductSEOSection.useDefaultUrl}}" time="30" stepKey="waitForUseDefaultUrlCheckbox"/> + <uncheckOption selector="{{AdminProductSEOSection.useDefaultUrl}}" stepKey="uncheckUseDefaultUrlCheckbox"/> + <fillField selector="{{AdminProductSEOSection.urlKeyInput}}" userInput="$$createProduct.custom_attributes[url_key]$$-updated" stepKey="changeUrlKey"/> + <actionGroup ref="saveProductForm" stepKey="saveProduct"/> + + <!--Select product and go toUpdate Attribute page--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="openProductsGrid"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterGridBySku"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <click selector="{{AdminProductFiltersSection.allCheckbox}}" stepKey="selectFilteredProduct"/> + <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickActionDropdown"/> + <click selector="{{AdminProductGridSection.bulkActionOption('Update attributes')}}" stepKey="clickBulkUpdateAttributes"/> + <waitForPageLoad stepKey="waitForUpdateAttributesPageLoad"/> + <seeInCurrentUrl url="{{AdminProductUpdateAttributesPage.url}}" stepKey="seeInUrlAttributeUpdatePage"/> + <click selector="{{AdminUpdateAttributesWebsiteSection.website}}" stepKey="openWebsitesTab"/> + <waitForAjaxLoad stepKey="waitForLoadWebSiteTab"/> + <click selector="{{AdminUpdateAttributesWebsiteSection.addProductToWebsite}}" stepKey="checkAddProductToWebsiteCheckbox"/> + <click selector="{{AdminUpdateAttributesHeaderSection.saveButton}}" stepKey="clickSave"/> + <see selector="{{AdminMessagesSection.success}}" userInput="A total of 1 record(s) were updated." stepKey="seeSaveSuccessMessage"/> + <!--Got to Store front product page and check url--> + <amOnPage url="{{StorefrontProductPage.url($$createProduct.custom_attributes[url_key]$$-updated)}}" stepKey="navigateToSimpleProductPage"/> + <seeInCurrentUrl url="{{StorefrontProductPage.url($$createProduct.custom_attributes[url_key]$$-updated)}}" stepKey="seeProductNewUrl"/> + <see selector="{{StorefrontProductInfoMainSection.productSku}}" userInput="$$createProduct.sku$$" stepKey="seeCorrectSku"/> + </test> +</tests> diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml index f79d59028c468..d20616b4384d1 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.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"> <!-- Checkout select Check/Money Order payment --> <actionGroup name="CheckoutSelectCheckMoneyOrderPaymentActionGroup"> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> @@ -37,7 +37,7 @@ <argument name="orderNumberMessage"/> <argument name="emailYouMessage"/> </arguments> - <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <waitForElementVisible selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> <see selector="{{CheckoutSuccessMainSection.success}}" userInput="{{orderNumberMessage}}" stepKey="seeOrderNumber"/> <see selector="{{CheckoutSuccessMainSection.success}}" userInput="{{emailYouMessage}}" stepKey="seeEmailYou"/> diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckCustomerInfoCreatedByGuestTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckCustomerInfoCreatedByGuestTest.xml new file mode 100644 index 0000000000000..32cc254543bca --- /dev/null +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckCustomerInfoCreatedByGuestTest.xml @@ -0,0 +1,63 @@ +<?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="StorefrontCheckCustomerInfoCreatedByGuestTest"> + <annotations> + <features value="Checkout"/> + <stories value="Check order customer information created by guest"/> + <title value="Check Order Customer Information Created By Guest"/> + <description value="Check customer information after placing the order as the guest who created an account"/> + <severity value="MAJOR"/> + <testCaseId value="MC-13839"/> + <useCaseId value="MAGETWO-95182"/> + <group value="checkout"/> + <group value="customer"/> + <group value="sales"/> + </annotations> + + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + + <after> + <deleteData createDataKey="createProduct" stepKey="deleteProduct" /> + <deleteData createDataKey="createCategory" stepKey="deleteCategory" /> + <actionGroup ref="logout" stepKey="logoutFromAdmin"/> + <actionGroup ref="CustomerLogoutStorefrontActionGroup" stepKey="customerLogoutFromStorefront" /> + </after> + + <amOnPage url="{{StorefrontProductPage.url($$createProduct.name$$)}}" stepKey="navigateToProductPage"/> + <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProductPage"> + <argument name="productName" value="$$createProduct.name$$"/> + </actionGroup> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart"/> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection"> + <argument name="customerVar" value="CustomerEntityOne"/> + <argument name="customerAddressVar" value="CustomerAddressSimple"/> + </actionGroup> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectPaymentMethod"/> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeOrder"> + <argument name="orderNumberMessage" value="CONST.successGuestCheckoutOrderNumberMessage"/> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> + </actionGroup> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + <click selector="{{CheckoutSuccessRegisterSection.createAccountButton}}" stepKey="clickCreateAccountButton"/> + <fillField selector="{{StorefrontCustomerCreateFormSection.passwordField}}" userInput="{{CustomerEntityOne.password}}" stepKey="typePassword"/> + <fillField selector="{{StorefrontCustomerCreateFormSection.confirmPasswordField}}" userInput="{{CustomerEntityOne.password}}" stepKey="typeConfirmationPassword"/> + <click selector="{{StorefrontCustomerCreateFormSection.createAccountButton}}" stepKey="clickOnCreateAccount"/> + <see selector="{{StorefrontMessagesSection.successMessage}}" userInput="Thank you for registering" stepKey="verifyAccountCreated"/> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdmin"/> + <amOnPage url="{{AdminOrderDetailsPage.url('$grabOrderNumber')}}" stepKey="navigateToOrderPage"/> + <see userInput="{{CustomerEntityOne.firstname}}" selector="{{AdminOrderDetailsInformationSection.customerName}}" stepKey="seeCustomerName"/> + </test> +</tests> diff --git a/app/code/Magento/Cms/Model/ResourceModel/Block.php b/app/code/Magento/Cms/Model/ResourceModel/Block.php index 9aab54b02bc14..9b4bc5ec3ea11 100644 --- a/app/code/Magento/Cms/Model/ResourceModel/Block.php +++ b/app/code/Magento/Cms/Model/ResourceModel/Block.php @@ -95,9 +95,11 @@ protected function _beforeSave(AbstractModel $object) } /** + * Get block id. + * * @param AbstractModel $object * @param mixed $value - * @param null $field + * @param string $field * @return bool|int|string * @throws LocalizedException * @throws \Exception @@ -183,10 +185,12 @@ public function getIsUniqueBlockToStores(AbstractModel $object) $entityMetadata = $this->metadataPool->getMetadata(BlockInterface::class); $linkField = $entityMetadata->getLinkField(); - if ($this->_storeManager->isSingleStoreMode()) { - $stores = [Store::DEFAULT_STORE_ID]; - } else { - $stores = (array)$object->getData('store_id'); + $stores = (array)$object->getData('store_id'); + $isDefaultStore = $this->_storeManager->isSingleStoreMode() + || array_search(Store::DEFAULT_STORE_ID, $stores) !== false; + + if (!$isDefaultStore) { + $stores[] = Store::DEFAULT_STORE_ID; } $select = $this->getConnection()->select() @@ -196,8 +200,11 @@ public function getIsUniqueBlockToStores(AbstractModel $object) 'cb.' . $linkField . ' = cbs.' . $linkField, [] ) - ->where('cb.identifier = ?', $object->getData('identifier')) - ->where('cbs.store_id IN (?)', $stores); + ->where('cb.identifier = ?', $object->getData('identifier')); + + if (!$isDefaultStore) { + $select->where('cbs.store_id IN (?)', $stores); + } if ($object->getId()) { $select->where('cb.' . $entityMetadata->getIdentifierField() . ' <> ?', $object->getId()); @@ -236,6 +243,8 @@ public function lookupStoreIds($id) } /** + * Save an object. + * * @param AbstractModel $object * @return $this * @throws \Exception diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminCmsBlockActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminCmsBlockActionGroup.xml new file mode 100644 index 0000000000000..597df165f61d1 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminCmsBlockActionGroup.xml @@ -0,0 +1,52 @@ +<?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="FillCmsBlockForm"> + <arguments> + <argument name="title" type="string" defaultValue="{{DefaultCmsBlock.title}}"/> + <argument name="identifier" type="string" defaultValue="{{DefaultCmsBlock.identifier}}"/> + <argument name="store" type="string" defaultValue="[All Store View]"/> + <argument name="content" type="string" defaultValue="{{DefaultCmsBlock.content}}"/> + </arguments> + <fillField selector="{{AdminCmsBlockContentSection.title}}" userInput="{{title}}" stepKey="fillFieldTitle"/> + <fillField selector="{{AdminCmsBlockContentSection.identifier}}" userInput="{{identifier}}" stepKey="fillFieldIdentifier"/> + <selectOption selector="{{AdminCmsBlockContentSection.storeView}}" parameterArray="{{store}}" stepKey="selectStore" /> + <fillField selector="{{AdminCmsBlockContentSection.content}}" userInput="{{content}}" stepKey="fillContentField"/> + </actionGroup> + <actionGroup name="DeleteCmsBlockActionGroup"> + <arguments> + <argument name="cmsBlockIdentifier" type="string" defaultValue="{{DefaultCmsBlock.identifier}}"/> + </arguments> + <amOnPage url="{{AdminCmsBlockGridPage.url}}" stepKey="navigateToCmsBlockListingPage"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingFiltersBeforeDelete"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openCmsBlockFilters"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('identifier')}}" userInput="{{cmsBlockIdentifier}}" stepKey="fillFilter"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFilters"/> + <click selector="{{CmsPagesPageActionsSection.select(cmsBlockIdentifier)}}" stepKey="clickOnSelect"/> + <click selector="{{CmsPagesPageActionsSection.delete(cmsBlockIdentifier)}}" stepKey="clickOnDelete"/> + <waitForElementVisible selector="{{AdminConfirmationModalSection.message}}" stepKey="waitForConfirmModal"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirm"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You deleted the block." stepKey="verifyBlockIsDeleted"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingFiltersAfterDelete"/> + </actionGroup> + <actionGroup name="NavigateToCreateCmsBlockActionGroup"> + <amOnPage url="{{AdminCmsBlockNewPage.url}}" stepKey="navigateToCreateCmsBlockPage"/> + </actionGroup> + <actionGroup name="SaveCmsBlockActionGroup"> + <scrollToTopOfPage stepKey="scrollToTopOfPage"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="clickSaveBlockButton"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the block." stepKey="verifyMessage"/> + </actionGroup> + <actionGroup name="SaveCmsBlockWithErrorActionGroup" extends="SaveCmsBlockActionGroup"> + <arguments> + <argument name="errorMessage" type="string" defaultValue="A block identifier with the same properties already exists in the selected store."/> + </arguments> + <see selector="{{AdminMessagesSection.error}}" userInput="{{errorMessage}}" stepKey="verifyMessage"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockNewPage.xml b/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockNewPage.xml new file mode 100644 index 0000000000000..2868d832ad762 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Page/AdminCmsBlockNewPage.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="AdminCmsBlockNewPage" url="/cms/block/new/" area="admin" module="Magento_Cms"> + <section name="AdminCmsBlockContentSection"/> + </page> +</pages> diff --git a/app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml b/app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml index 9614f13f9e3d3..20e55c49ec235 100644 --- a/app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml +++ b/app/code/Magento/Cms/Test/Mftf/Section/AdminCmsBlockContentSection.xml @@ -11,5 +11,8 @@ <section name="AdminCmsBlockContentSection"> <element name="content" type="textarea" selector="#cms_block_form_content"/> <element name="insertWidgetButton" type="button" selector=".scalable.action-add-widget.plugin"/> + <element name="title" type="input" selector="input[name=title]"/> + <element name="identifier" type="input" selector="input[name=identifier]"/> + <element name="storeView" type="multiselect" selector="select[name=store_id]"/> </section> </sections> diff --git a/app/code/Magento/Cms/Test/Mftf/Test/CheckCreateStaticBlockOnDuplicateIdentifierTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/CheckCreateStaticBlockOnDuplicateIdentifierTest.xml new file mode 100644 index 0000000000000..ac1b68269740f --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/Test/CheckCreateStaticBlockOnDuplicateIdentifierTest.xml @@ -0,0 +1,55 @@ +<?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="CheckCreateStaticBlockOnDuplicateIdentifierTest"> + <annotations> + <features value="Cms"/> + <stories value="Create CMS Block"/> + <title value="Check static blocks: ID should be unique per Store View"/> + <description value="Check static blocks: ID should be unique per Store View"/> + <severity value="CRITICAL"/> + <testCaseId value="MC-13912"/> + <useCaseId value="MAGETWO-86215"/> + <group value="cms"/> + <group value="WYSIWYGDisabled"/> + </annotations> + <before> + <actionGroup ref="LoginAsAdmin" stepKey="LoginAsAdmin"/> + <actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createSecondWebsite"> + <argument name="newWebsiteName" value="{{SecondWebsite.name}}"/> + <argument name="websiteCode" value="{{SecondWebsite.code}}"/> + </actionGroup> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createSecondStoreGroup"> + <argument name="website" value="{{SecondWebsite.name}}"/> + <argument name="storeGroupName" value="{{SecondStoreGroupUnique.name}}"/> + <argument name="storeGroupCode" value="{{SecondStoreGroupUnique.code}}"/> + </actionGroup> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createSecondStoreView"> + <argument name="storeGroup" value="SecondStoreGroupUnique"/> + <argument name="customStore" value="SecondStoreUnique"/> + </actionGroup> + </before> + <after> + <actionGroup ref="DeleteCmsBlockActionGroup" stepKey="deleteCMSBlockActionGroup"/> + <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteWebsite"> + <argument name="websiteName" value="{{SecondWebsite.name}}"/> + </actionGroup> + <actionGroup ref="logout" stepKey="logout"/> + </after> + <actionGroup ref="NavigateToCreateCmsBlockActionGroup" stepKey="navigateToCreateCmsBlock"/> + <actionGroup ref="FillCmsBlockForm" stepKey="fillCmsBlockForm"/> + <actionGroup ref="SaveCmsBlockActionGroup" stepKey="saveCmsBlock"/> + <actionGroup ref="NavigateToCreateCmsBlockActionGroup" stepKey="navigateToCreateDuplicateCmsBlock"/> + <actionGroup ref="FillCmsBlockForm" stepKey="fillDuplicateCmsBlockForm"> + <argument name="store" value="[{{_defaultStore.name}},{{SecondStoreUnique.name}}]"/> + </actionGroup> + <actionGroup ref="SaveCmsBlockWithErrorActionGroup" stepKey="assertErrorMessageOnSave"/> + </test> +</tests> diff --git a/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAddCustomerAddressActionGroup.xml b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAddCustomerAddressActionGroup.xml new file mode 100644 index 0000000000000..1ffc258e78a43 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/ActionGroup/AdminAddCustomerAddressActionGroup.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminAddCustomerAddressWithRegionTypeSelectActionGroup" > + <arguments> + <argument name="customerAddress" defaultValue="CustomerAddressSimple"/> + </arguments> + <click selector="{{AdminCustomerAccountAddressSection.addresses}}" stepKey="proceedToAddresses"/> + <click selector="{{AdminCustomerAccountAddressSection.addNewAddress}}" stepKey="addNewAddresses"/> + <fillField userInput="{{customerAddress.street[0]}}" selector="{{AdminCustomerAccountNewAddressSection.street}}" stepKey="fillStreetAddress"/> + <fillField userInput="{{customerAddress.city}}" selector="{{AdminCustomerAccountNewAddressSection.city}}" stepKey="fillCity"/> + <selectOption userInput="{{customerAddress.country_id}}" selector="{{AdminCustomerAccountNewAddressSection.country}}" stepKey="selectCountry"/> + <selectOption userInput="{{customerAddress.state}}" selector="{{AdminCustomerAccountNewAddressSection.regionId}}" stepKey="selectState"/> + <fillField userInput="{{customerAddress.postcode}}" selector="{{AdminCustomerAccountNewAddressSection.zip}}" stepKey="fillZipCode"/> + <fillField userInput="{{customerAddress.telephone}}" selector="{{AdminCustomerAccountNewAddressSection.phone}}" stepKey="fillPhone"/> + <click selector="{{AdminMainActionsSection.save}}" stepKey="saveCustomer"/> + <see userInput="You saved the customer." selector="{{AdminMessagesSection.success}}" stepKey="customerIsSaved"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml b/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml index 72d5d90bdc05f..7cd36c12c80bd 100644 --- a/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml +++ b/app/code/Magento/Customer/Test/Mftf/Page/AdminEditCustomerPage.xml @@ -12,5 +12,6 @@ <section name="AdminCustomerMainActionsSection"/> <section name="AdminCustomerAccountAddressSection"/> <section name="AdminCustomerAccountEditAddressSection"/> + <section name="AdminCustomerAccountNewAddressSection"/> </page> </pages> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml index db9619dde671f..70042e2a71467 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountAddressSection.xml @@ -7,7 +7,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd"> <section name="AdminCustomerAccountAddressSection"> - <element name="addresses" type="button" selector="a#tab_address"/> - <element name="addNewAddress" type="button" selector=".address-list-actions button.scalable.add span"/> + <element name="addresses" type="button" selector="#tab_address" timeout="30"/> + <element name="addNewAddress" type="button" selector=".address-list-actions button.scalable.add span" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountNewAddressSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountNewAddressSection.xml new file mode 100644 index 0000000000000..8445343c9b9c0 --- /dev/null +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerAccountNewAddressSection.xml @@ -0,0 +1,19 @@ +<!-- + /** + * 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="AdminCustomerAccountNewAddressSection"> + <element name="firstName" type="button" selector="input[name*='address'][name*='new'][name*='firstname']"/> + <element name="lastName" type="button" selector="input[name*='address'][name*='new'][name*='lastname']"/> + <element name="street" type="button" selector="input[name*='new'][name*='street']"/> + <element name="city" type="input" selector="input[name*='new'][name*='city']"/> + <element name="country" type="select" selector="select[name*='address'][name*='new'][name*='country']" timeout="10"/> + <element name="regionId" type="select" selector="select[name*='address'][name*='new'][name*='region_id']"/> + <element name="zip" type="input" selector="input[name*='address'][name*='new'][name*='postcode']"/> + <element name="phone" type="text" selector="input[name*='address'][name*='new'][name*='telephone']" /> + </section> +</sections> diff --git a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml index 0a77890033295..9553752539757 100644 --- a/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml +++ b/app/code/Magento/Customer/Test/Mftf/Section/AdminCustomerMainActionsSection.xml @@ -7,8 +7,9 @@ --> <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="AdminCustomerMainActionsSection"> <element name="saveButton" type="button" selector="#save" timeout="30"/> + <element name="deleteButton" type="button" selector="div.page-actions button.delete" timeout="30"/> </section> </sections> diff --git a/app/code/Magento/Eav/Model/Entity/Type.php b/app/code/Magento/Eav/Model/Entity/Type.php index aa298d7d547bf..5ee15287e8899 100644 --- a/app/code/Magento/Eav/Model/Entity/Type.php +++ b/app/code/Magento/Eav/Model/Entity/Type.php @@ -167,11 +167,8 @@ public function getAttributeCollection($setId = null) */ protected function _getAttributeCollection() { - $collection = $this->_attributeFactory->create()->getCollection(); - $objectsModel = $this->getAttributeModel(); - if ($objectsModel) { - $collection->setModel($objectsModel); - } + $collection = $this->_universalFactory->create($this->getEntityAttributeCollection()); + $collection->setItemObjectClass($this->getAttributeModel()); return $collection; } diff --git a/app/code/Magento/Reports/Block/Adminhtml/Sales/Sales/Grid.php b/app/code/Magento/Reports/Block/Adminhtml/Sales/Sales/Grid.php index 1f90309721c23..9c80f6aa423b8 100644 --- a/app/code/Magento/Reports/Block/Adminhtml/Sales/Sales/Grid.php +++ b/app/code/Magento/Reports/Block/Adminhtml/Sales/Sales/Grid.php @@ -6,23 +6,58 @@ namespace Magento\Reports\Block\Adminhtml\Sales\Sales; +use Magento\Framework\DataObject; use Magento\Reports\Block\Adminhtml\Grid\Column\Renderer\Currency; +use Magento\Framework\App\ObjectManager; +use Magento\Sales\Model\Order\ConfigFactory; +use Magento\Sales\Model\Order; /** * Adminhtml sales report grid block * - * @author Magento Core Team <core@magentocommerce.com> * @SuppressWarnings(PHPMD.DepthOfInheritance) */ class Grid extends \Magento\Reports\Block\Adminhtml\Grid\AbstractGrid { /** - * GROUP BY criteria - * * @var string */ protected $_columnGroupBy = 'period'; + /** + * @var ConfigFactory + */ + private $configFactory; + + /** + * @param \Magento\Backend\Block\Template\Context $context + * @param \Magento\Backend\Helper\Data $backendHelper + * @param \Magento\Reports\Model\ResourceModel\Report\Collection\Factory $resourceFactory + * @param \Magento\Reports\Model\Grouped\CollectionFactory $collectionFactory + * @param \Magento\Reports\Helper\Data $reportsData + * @param array $data + * @param ConfigFactory|null $configFactory + */ + public function __construct( + \Magento\Backend\Block\Template\Context $context, + \Magento\Backend\Helper\Data $backendHelper, + \Magento\Reports\Model\ResourceModel\Report\Collection\Factory $resourceFactory, + \Magento\Reports\Model\Grouped\CollectionFactory $collectionFactory, + \Magento\Reports\Helper\Data $reportsData, + array $data = [], + ConfigFactory $configFactory = null + ) { + parent::__construct( + $context, + $backendHelper, + $resourceFactory, + $collectionFactory, + $reportsData, + $data + ); + $this->configFactory = $configFactory ?: ObjectManager::getInstance()->get(ConfigFactory::class); + } + /** * {@inheritdoc} * @codeCoverageIgnore @@ -328,4 +363,31 @@ protected function _prepareColumns() return parent::_prepareColumns(); } + + /** + * @inheritdoc + * + * Filter canceled statuses for orders. + * + * @return Grid + */ + protected function _prepareCollection() + { + /** @var DataObject $filterData */ + $filterData = $this->getData('filter_data'); + if (!$filterData->hasData('order_statuses')) { + $orderConfig = $this->configFactory->create(); + $statusValues = []; + $canceledStatuses = $orderConfig->getStateStatuses(Order::STATE_CANCELED); + $statusCodes = array_keys($orderConfig->getStatuses()); + foreach ($statusCodes as $code) { + if (!isset($canceledStatuses[$code])) { + $statusValues[] = $code; + } + } + $filterData->setData('order_statuses', $statusValues); + } + + return parent::_prepareCollection(); + } } diff --git a/app/code/Magento/Reports/Test/Mftf/ActionGroup/GenerateOrderReportActionGroup.xml b/app/code/Magento/Reports/Test/Mftf/ActionGroup/GenerateOrderReportActionGroup.xml new file mode 100644 index 0000000000000..8ddfd4092645f --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/ActionGroup/GenerateOrderReportActionGroup.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="GenerateOrderReportActionGroup"> + <arguments> + <argument name="orderFromDate" type="string"/> + <argument name="orderToDate" type="string"/> + </arguments> + <click selector="{{AdminOrderReportMainActionsSection.refreshStatistics}}" stepKey="refreshStatistics"/> + <fillField selector="{{AdminOrderReportFilterSection.dateFrom}}" userInput="{{orderFromDate}}" stepKey="fillFromDate"/> + <fillField selector="{{AdminOrderReportFilterSection.dateTo}}" userInput="{{orderToDate}}" stepKey="fillToDate"/> + <selectOption selector="{{AdminOrderReportFilterSection.orderStatus}}" userInput="Any" stepKey="selectAnyOption"/> + <click selector="{{AdminOrderReportMainActionsSection.showReport}}" stepKey="showReport"/> + </actionGroup> +</actionGroups> diff --git a/app/code/Magento/Reports/Test/Mftf/Page/AdminOrdersReportPage.xml b/app/code/Magento/Reports/Test/Mftf/Page/AdminOrdersReportPage.xml new file mode 100644 index 0000000000000..f0b51f6e39357 --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/Page/AdminOrdersReportPage.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="AdminOrdersReportPage" url="reports/report_sales/sales/" area="admin" module="Reports"> + <section name="AdminOrderReportFilterSection"/> + <section name="AdminOrderReportMainActionsSection"/> + <section name="AdminOrderReportTableSection"/> + </page> +</pages> diff --git a/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportFilterSection.xml b/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportFilterSection.xml new file mode 100644 index 0000000000000..33527e1262020 --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportFilterSection.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="AdminOrderReportFilterSection"> + <element name="dateFrom" type="input" selector="#sales_report_from"/> + <element name="dateTo" type="input" selector="#sales_report_to"/> + <element name="orderStatus" type="select" selector="#sales_report_show_order_statuses"/> + </section> +</sections> diff --git a/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportMainActionsSection.xml b/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportMainActionsSection.xml new file mode 100644 index 0000000000000..c4a96537740ee --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportMainActionsSection.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="AdminOrderReportMainActionsSection"> + <element name="showReport" type="button" time="30" selector="#filter_form_submit"/> + <element name="refreshStatistics" type="text" time="30" selector="//a[contains(text(), 'here')]"/> + </section> +</sections> diff --git a/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportTableSection.xml b/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportTableSection.xml new file mode 100644 index 0000000000000..e920d28bcf386 --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/Section/AdminOrderReportTableSection.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="AdminOrderReportTableSection"> + <element name="ordersCount" type="text" selector=".totals .col-orders.col-orders_count.col-number"/> + <element name="canceledOrders" type="text" selector=".totals .col-canceled.col-total_canceled_amount.a-right"/> + </section> +</sections> diff --git a/app/code/Magento/Reports/Test/Mftf/Test/CancelOrdersInOrderSalesReportTest.xml b/app/code/Magento/Reports/Test/Mftf/Test/CancelOrdersInOrderSalesReportTest.xml new file mode 100644 index 0000000000000..009e4b8e5f6f1 --- /dev/null +++ b/app/code/Magento/Reports/Test/Mftf/Test/CancelOrdersInOrderSalesReportTest.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd"> + <test name="CancelOrdersInOrderSalesReportTest"> + <annotations> + <features value="Reports"/> + <stories value="Order Sales Report"/> + <group value="reports"/> + <title value="Canceled orders in order sales report"/> + <description value="Verify canceling of orders in order sales report"/> + <severity value="MAJOR"/> + <testCaseId value="MC-13838"/> + <useCaseId value="MAGETWO-95463"/> + </annotations> + <before> + <!-- create new product --> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="SimpleProduct" stepKey="createSimpleProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <!-- create new customer--> + <createData entity="Simple_US_Customer" stepKey="createCustomer"/> + <!--login to Admin--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createCustomer" stepKey="deleteCustomer"/> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Create new order--> + <comment userInput="Admin creates order" stepKey="adminCreateOrderComment"/> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="startToCreateNewOrder"> + <argument name="customer" value="$$createCustomer$$"/> + </actionGroup> + <actionGroup ref="addSimpleProductToOrder" stepKey="addSimpleProductToOrderWithUserDefinedQty"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="quantity" value="1"/> + </actionGroup> + <!-- Select shipping --> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShipping"/> + <!--Select payment--> + <actionGroup ref="SelectCheckMoneyPaymentMethod" stepKey="selectCheckMoneyPayment"/> + <!--Submit Order--> + <click selector="{{AdminOrderFormActionSection.submitOrder}}" stepKey="clickSubmitOrder"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You created the order." stepKey="seeSuccessMessage"/> + <!--Create order invoice--> + <comment userInput="Admin creates invoice for order" stepKey="adminCreateInvoiceComment" /> + <actionGroup ref="StartCreateInvoiceFromOrderPage" stepKey="createInvoice"/> + <actionGroup ref="SubmitInvoice" stepKey="submitInvoice"/> + <!--Ship Order--> + <comment userInput="Admin creates shipment" stepKey="adminCreatesShipmentComment"/> + <actionGroup ref="StartCreateShipmentFromOrderPage" stepKey="createShipment"/> + <actionGroup ref="SubmitShipment" stepKey="submitShipment"/> + + <!--Create new order--> + <comment userInput="Admin creates order" stepKey="adminCreateOrderComment1"/> + <actionGroup ref="navigateToNewOrderPageExistingCustomer" stepKey="startToCreateNewOrder1"> + <argument name="customer" value="$$createCustomer$$"/> + </actionGroup> + <actionGroup ref="addSimpleProductToOrder" stepKey="addSimpleProductToOrderWithUserDefinedQty1"> + <argument name="product" value="$$createSimpleProduct$$"/> + <argument name="quantity" value="1"/> + </actionGroup> + <!-- Select shipping --> + <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShipping1"/> + <!--Select payment--> + <actionGroup ref="SelectCheckMoneyPaymentMethod" stepKey="selectCheckMoneyPayment1"/> + <!--Submit Order--> + <click selector="{{AdminOrderFormActionSection.submitOrder}}" stepKey="clickSubmitOrder1"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You created the order." stepKey="seeSuccessMessage1"/> + <!-- Cancel order --> + <actionGroup ref="cancelPendingOrder" stepKey="cancelOrder"/> + + <!-- Generate Order report --> + <amOnPage url="{{AdminOrdersReportPage.url}}" stepKey="goToAdminOrdersReportPage"/> + <!-- Get date --> + <generateDate date="+0 day" format="m/d/Y" stepKey="generateEndDate"/> + <generateDate date="-1 day" format="m/d/Y" stepKey="generateStartDate"/> + <actionGroup ref="GenerateOrderReportActionGroup" stepKey="generateReportAfterCancelOrder"> + <argument name="orderFromDate" value="$generateStartDate"/> + <argument name="orderToDate" value="$generateEndDate"/> + </actionGroup> + <waitForElement selector="{{AdminOrderReportTableSection.ordersCount}}" stepKey="waitForOrdersCount"/> + <see selector="{{AdminOrderReportTableSection.canceledOrders}}" userInput="$0.00" stepKey="seeCanceledOrderPrice"/> + </test> +</tests> diff --git a/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php b/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php index 9857fa39fa51a..80e909941c5ce 100644 --- a/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php +++ b/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php @@ -57,6 +57,17 @@ public function execute(Observer $observer) $orderId = $delegateData['__sales_assign_order_id']; $order = $this->orderRepository->get($orderId); if (!$order->getCustomerId() && $customer->getId()) { + // Assign customer info to order after customer creation. + $order->setCustomerId($customer->getId()) + ->setCustomerIsGuest(0) + ->setCustomerEmail($customer->getEmail()) + ->setCustomerFirstname($customer->getFirstname()) + ->setCustomerLastname($customer->getLastname()) + ->setCustomerMiddlename($customer->getMiddlename()) + ->setCustomerPrefix($customer->getPrefix()) + ->setCustomerSuffix($customer->getSuffix()) + ->setCustomerGroupId($customer->getGroupId()); + $this->assignmentService->execute($order, $customer); } } diff --git a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml index cb761dc358abb..d196783744c46 100644 --- a/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml +++ b/app/code/Magento/Sales/Test/Mftf/Test/AdminAbleToShipPartiallyInvoicedItemsTest.xml @@ -14,9 +14,6 @@ <severity value="CRITICAL"/> <testCaseId value="MAGETWO-95524"/> <group value="sales"/> - <skip> - <issueId value="MAGETWO-97664"/> - </skip> </annotations> <before> <createData entity="_defaultCategory" stepKey="createCategory"/> diff --git a/app/code/Magento/Sales/Test/Unit/Observer/AssignOrderToCustomerObserverTest.php b/app/code/Magento/Sales/Test/Unit/Observer/AssignOrderToCustomerObserverTest.php index 18371274049e3..8890f01130c82 100644 --- a/app/code/Magento/Sales/Test/Unit/Observer/AssignOrderToCustomerObserverTest.php +++ b/app/code/Magento/Sales/Test/Unit/Observer/AssignOrderToCustomerObserverTest.php @@ -52,9 +52,10 @@ protected function setUp() * * @dataProvider getCustomerIds * @param null|int $customerId + * @param null|int $customerOrderId * @return void */ - public function testAssignOrderToCustomerAfterGuestOrder($customerId) + public function testAssignOrderToCustomerAfterGuestOrder($customerId, $customerOrderId) { $orderId = 1; /** @var Observer|PHPUnit_Framework_MockObject_MockObject $observerMock */ @@ -64,7 +65,12 @@ public function testAssignOrderToCustomerAfterGuestOrder($customerId) ->setMethods(['getData']) ->getMock(); /** @var CustomerInterface|PHPUnit_Framework_MockObject_MockObject $customerMock */ - $customerMock = $this->createMock(CustomerInterface::class); + $customerMock = $this->getMockBuilder(CustomerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $customerMock->expects($this->any()) + ->method('getId') + ->willReturn($customerId); /** @var OrderInterface|PHPUnit_Framework_MockObject_MockObject $orderMock */ $orderMock = $this->getMockBuilder(OrderInterface::class) ->disableOriginalConstructor() @@ -75,13 +81,24 @@ public function testAssignOrderToCustomerAfterGuestOrder($customerId) ['delegate_data', null, ['__sales_assign_order_id' => $orderId]], ['customer_data_object', null, $customerMock] ]); - $orderMock->expects($this->once())->method('getCustomerId')->willReturn($customerId); + $orderMock->expects($this->any())->method('getCustomerId')->willReturn($customerOrderId); $this->orderRepositoryMock->expects($this->once())->method('get')->with($orderId) ->willReturn($orderMock); - if ($customerId) { + if (!$customerOrderId && $customerId) { + $orderMock->expects($this->once())->method('setCustomerId')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerIsGuest')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerEmail')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerFirstname')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerLastname')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerMiddlename')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerPrefix')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerSuffix')->willReturn($orderMock); + $orderMock->expects($this->once())->method('setCustomerGroupId')->willReturn($orderMock); + $this->assignmentMock->expects($this->once())->method('execute')->with($orderMock, $customerMock); $this->sut->execute($observerMock); + return; } @@ -94,8 +111,12 @@ public function testAssignOrderToCustomerAfterGuestOrder($customerId) * * @return array */ - public function getCustomerIds() + public function getCustomerIds(): array { - return [[null, 1]]; + return [ + [null, null], + [1, null], + [1, 1], + ]; } } diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml index a73740c249b67..b0b52b199978a 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/creditmemo/create/items.phtml @@ -140,67 +140,76 @@ </section> <script> -require(['jquery', 'prototype'], function(jQuery){ +require(['jquery'], function(jQuery){ //<![CDATA[ -var submitButtons = $$('.submit-button'); -var updateButtons = $$('.update-button,.update-totals-button'); -var fields = $$('.qty-input,.order-subtotal-table input[type="text"]'); +var submitButtons = jQuery('.submit-button'); +var updateButtons = jQuery('.update-button,.update-totals-button'); +var fields = jQuery('.qty-input,.order-subtotal-table input[type="text"]'); -updateButtons.each(function (elem) {elem.disabled=true;elem.addClassName('disabled');}); +function enableButtons(buttons) { + buttons.removeClass('disabled').prop('disabled', false); +}; -for(var i=0;i<fields.length;i++){ - fields[i].observe('change', checkButtonsRelation) - fields[i].baseValue = fields[i].value; -} +function disableButtons(buttons) { + buttons.addClass('disabled').prop('disabled', true); +}; + +disableButtons(updateButtons); + +fields.on('change', checkButtonsRelation); +fields.each(function (i, elem) { + elem.baseValue = elem.value; +}); function checkButtonsRelation() { var hasChanges = false; - fields.each(function (elem) { + fields.each(function (i, elem) { if (elem.baseValue != elem.value) { hasChanges = true; } }.bind(this)); if (hasChanges) { - submitButtons.each(function (elem) {elem.disabled=true;elem.addClassName('disabled');}); - updateButtons.each(function (elem) {elem.disabled=false;elem.removeClassName('disabled');}); + disableButtons(submitButtons); + enableButtons(updateButtons); } else { - submitButtons.each(function (elem) {elem.disabled=false;elem.removeClassName('disabled');}); - updateButtons.each(function (elem) {elem.disabled=true;elem.addClassName('disabled');}); + enableButtons(submitButtons); + disableButtons(updateButtons); } } submitCreditMemo = function() { - if ($('creditmemo_do_offline')) $('creditmemo_do_offline').value=0; + var creditMemoOffline = jQuery('#creditmemo_do_offline'); + if (creditMemoOffline.length) { + creditMemoOffline.prop('value', 0); + } // Temporary solution will be replaced after refactoring order functionality jQuery('#edit_form').triggerHandler('save'); } submitCreditMemoOffline = function() { - if ($('creditmemo_do_offline')) $('creditmemo_do_offline').value=1; + var creditMemoOffline = jQuery('#creditmemo_do_offline'); + if (creditMemoOffline.length) { + creditMemoOffline.prop('value', 1); + } // Temporary solution will be replaced after refactoring order functionality jQuery('#edit_form').triggerHandler('save'); } -var sendEmailCheckbox = $('send_email'); - -if (sendEmailCheckbox) { - var notifyCustomerCheckbox = $('notify_customer'); - var creditmemoCommentText = $('creditmemo_comment_text'); - Event.observe(sendEmailCheckbox, 'change', bindSendEmail); +var sendEmailCheckbox = jQuery('#send_email'); +if (sendEmailCheckbox.length) { + var notifyCustomerCheckbox = jQuery('#notify_customer'); + sendEmailCheckbox.on('change', bindSendEmail); bindSendEmail(); } -function bindSendEmail() -{ - if (sendEmailCheckbox.checked == true) { - notifyCustomerCheckbox.disabled = false; - //creditmemoCommentText.disabled = false; +function bindSendEmail() { + if (sendEmailCheckbox.prop('checked') == true) { + notifyCustomerCheckbox.prop('disabled', false); } else { - notifyCustomerCheckbox.disabled = true; - //creditmemoCommentText.disabled = true; + notifyCustomerCheckbox.prop('disabled', true); } } diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/invoice/create/items.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/invoice/create/items.phtml index 4a77c3b166de9..0d873645bce86 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/invoice/create/items.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/invoice/create/items.phtml @@ -134,56 +134,61 @@ </section> <script> -require(['jquery', 'prototype'], function(jQuery){ +require(['jquery'], function(jQuery){ //<![CDATA[ -var submitButtons = $$('.submit-button'); -var updateButtons = $$('.update-button'); +var submitButtons = jQuery('.submit-button'); +var updateButtons = jQuery('.update-button'); var enableSubmitButtons = <?= (int) !$block->getDisableSubmitButton() ?>; -var fields = $$('.qty-input'); +var fields = jQuery('.qty-input'); -updateButtons.each(function (elem) {elem.disabled=true;elem.addClassName('disabled');}); +function enableButtons(buttons) { + buttons.removeClass('disabled').prop('disabled', false); +}; -for(var i=0;i<fields.length;i++){ - jQuery(fields[i]).on('keyup', checkButtonsRelation); - fields[i].baseValue = fields[i].value; -} +function disableButtons(buttons) { + buttons.addClass('disabled').prop('disabled', true); +}; + +disableButtons(updateButtons); + +fields.on('keyup', checkButtonsRelation); +fields.each(function (i, elem) { + elem.baseValue = elem.value; +}); function checkButtonsRelation() { var hasChanges = false; - fields.each(function (elem) { + fields.each(function (i, elem) { if (elem.baseValue != elem.value) { hasChanges = true; } }.bind(this)); if (hasChanges) { - submitButtons.each(function (elem) {elem.disabled=true;elem.addClassName('disabled');}); - updateButtons.each(function (elem) {elem.disabled=false;elem.removeClassName('disabled');}); + disableButtons(submitButtons); + enableButtons(updateButtons); } else { if (enableSubmitButtons) { - submitButtons.each(function (elem) {elem.disabled=false;elem.removeClassName('disabled');}); + enableButtons(submitButtons); } - updateButtons.each(function (elem) {elem.disabled=true;elem.addClassName('disabled');}); + disableButtons(updateButtons); } } -var sendEmailCheckbox = $('send_email'); -if (sendEmailCheckbox) { - var notifyCustomerCheckbox = $('notify_customer'); - var invoiceCommentText = $('invoice_comment_text'); - Event.observe(sendEmailCheckbox, 'change', bindSendEmail); +var sendEmailCheckbox = jQuery('#send_email'); +if (sendEmailCheckbox.length) { + var notifyCustomerCheckbox = jQuery('#notify_customer'); + sendEmailCheckbox.on('change', bindSendEmail); bindSendEmail(); } function bindSendEmail() { - if (sendEmailCheckbox.checked == true) { - notifyCustomerCheckbox.disabled = false; - //invoiceCommentText.disabled = false; + if (sendEmailCheckbox.prop('checked') == true) { + notifyCustomerCheckbox.prop('disabled', false); } else { - notifyCustomerCheckbox.disabled = true; - //invoiceCommentText.disabled = true; + notifyCustomerCheckbox.prop('disabled', true); } } diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml index c0589f3acfda6..e85eea62d473e 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataProfileSchema.xsd"> <entity name="ApiSalesRule" type="SalesRule"> <data key="name" unique="suffix">salesRule</data> <data key="description">Sales Rule Descritpion</data> @@ -141,7 +141,6 @@ <data key="uses_per_coupon">0</data> <data key="simple_free_shipping">0</data> </entity> - <entity name="SalesRuleSpecificCouponWithFixedDiscount" type="SalesRule"> <data key="name" unique="suffix">SimpleSalesRule</data> <data key="description">Sales Rule Description</data> @@ -168,6 +167,36 @@ <data key="uses_per_coupon">10</data> <data key="simple_free_shipping">1</data> </entity> + <entity name="CartPriceRuleWithRewardPointsOnly" type="SalesRule"> + <data key="name" unique="suffix">SalesRuleReward</data> + <data key="description">Sales Rule with Reward Point</data> + <array key="website_ids"> + <item>1</item> + </array> + <array key="customer_group_ids"> + <item>0</item> + <item>1</item> + <item>2</item> + <item>3</item> + </array> + <data key="uses_per_customer">10</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">0</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">10</data> + <data key="simple_free_shipping">0</data> + <requiredEntity type="sales-rule-extension-attribute">SalesRuleExtensionAttribute</requiredEntity> + </entity> <entity name="PriceRuleWithCondition" type="SalesRule"> <data key="name" unique="suffix">SalesRule</data> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleExtensionAttributeData.xml b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleExtensionAttributeData.xml new file mode 100644 index 0000000000000..43ff4d897c143 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/Data/SalesRuleExtensionAttributeData.xml @@ -0,0 +1,13 @@ +<?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="SalesRuleExtensionAttribute" type="sales-rule-extension-attribute"> + <data key="reward_points_delta">200</data> + </entity> +</entities> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Metadata/sales-rule-extension-attribute-meta.xml b/app/code/Magento/SalesRule/Test/Mftf/Metadata/sales-rule-extension-attribute-meta.xml new file mode 100644 index 0000000000000..51c4ac24a7426 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Mftf/Metadata/sales-rule-extension-attribute-meta.xml @@ -0,0 +1,12 @@ +<!-- + /** + * 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="SetSalesRuleExtensionAttribute" dataType="sales-rule-extension-attribute" type="create"> + <field key="reward_points_delta">integer</field> + </operation> +</operations> diff --git a/app/code/Magento/SalesRule/Test/Mftf/Metadata/sales_rule-meta.xml b/app/code/Magento/SalesRule/Test/Mftf/Metadata/sales_rule-meta.xml index 0d4c4356a20a7..38009c510d2be 100644 --- a/app/code/Magento/SalesRule/Test/Mftf/Metadata/sales_rule-meta.xml +++ b/app/code/Magento/SalesRule/Test/Mftf/Metadata/sales_rule-meta.xml @@ -6,7 +6,7 @@ */ --> <operations 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/dataOperation.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:mftf:DataGenerator/etc/dataOperation.xsd"> <operation name="CreateSalesRule" dataType="SalesRule" type="create" auth="adminOauth" url="/V1/salesRules" method="POST"> <contentType>application/json</contentType> <object key="rule" dataType="SalesRule"> @@ -30,6 +30,7 @@ <field key="simple_free_shipping">string</field> <field key="stop_rules_processing">boolean</field> <field key="is_advanced">boolean</field> + <field key="extension_attributes">sales-rule-extension-attribute</field> <array key="store_labels"> <!-- specify object name as array value --> <value>SalesRuleStoreLabel</value> @@ -67,9 +68,6 @@ <field key="value">string</field> <field key="extension_attributes">empty_extension_attribute</field> </object> - <object dataType="ExtensionAttribute" key="extension_attributes"> - <field key="reward_points_delta">integer</field> - </object> </object> </operation> <operation name="DeleteSalesRule" dataType="SalesRule" type="delete" auth="adminOauth" url="/V1/salesRules/{rule_id}" method="DELETE"> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreViewActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreViewActionGroup.xml index f1c6f4d87e0d6..2f541feacd9c2 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreViewActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminCreateStoreViewActionGroup.xml @@ -24,8 +24,8 @@ <waitForElementVisible selector="{{AdminConfirmationModalSection.ok}}" stepKey="waitForModal" /> <see selector="{{AdminConfirmationModalSection.title}}" userInput="Warning message" stepKey="seeWarning" /> <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="dismissModal" /> - <waitForElementVisible selector="{{AdminStoresGridSection.storeFilterTextField}}" stepKey="waitForPageReolad"/> - <see userInput="You saved the store view." stepKey="seeSavedMessage" /> + <waitForElementVisible selector="{{AdminMessagesSection.success}}" stepKey="waitForPageReolad"/> + <see selector="{{AdminMessagesSection.success}}" userInput="You saved the store view." stepKey="seeSavedMessage" /> </actionGroup> <actionGroup name="AdminCreateStoreViewUseStringArgumentsActionGroup" extends="AdminCreateStoreViewActionGroup"> <arguments> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminSwitchStoreViewActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminSwitchStoreViewActionGroup.xml index d540a0000655f..1c56c3cc44220 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminSwitchStoreViewActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/AdminSwitchStoreViewActionGroup.xml @@ -16,6 +16,7 @@ <waitForElementVisible selector="{{AdminConfirmationModalSection.ok}}" stepKey="waitingForInformationModal"/> <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmScopeSwitch"/> <waitForPageLoad stepKey="waitForScopeSwitched"/> + <scrollToTopOfPage stepKey="scrollToStoreSwitcher"/> <see userInput="{{scopeName}}" selector="{{AdminMainActionsSection.storeSwitcher}}" stepKey="seeNewScopeName"/> </actionGroup> diff --git a/app/code/Magento/Store/Test/Mftf/ActionGroup/StorefrontSwitchStoreViewActionGroup.xml b/app/code/Magento/Store/Test/Mftf/ActionGroup/StorefrontSwitchStoreViewActionGroup.xml index e6ebd229e4683..c62ed55c7df49 100644 --- a/app/code/Magento/Store/Test/Mftf/ActionGroup/StorefrontSwitchStoreViewActionGroup.xml +++ b/app/code/Magento/Store/Test/Mftf/ActionGroup/StorefrontSwitchStoreViewActionGroup.xml @@ -13,7 +13,7 @@ </arguments> <click selector="{{StorefrontHeaderSection.storeViewSwitcher}}" stepKey="clickStoreViewSwitcher"/> <waitForElementVisible selector="{{StorefrontHeaderSection.storeViewDropdown}}" stepKey="waitForStoreViewDropdown"/> - <click selector="{{StorefrontHeaderSection.storeViewOption(storeView.name)}}" stepKey="clickSelectStoreView"/> + <click selector="{{StorefrontHeaderSection.storeViewOption(storeView.code)}}" stepKey="clickSelectStoreView"/> <waitForPageLoad stepKey="waitForPageLoad"/> </actionGroup> </actionGroups>