From 4be33726b69905d776649bcc8c5dc973669d6b61 Mon Sep 17 00:00:00 2001 From: nmalevanec Date: Thu, 21 May 2020 15:52:56 +0300 Subject: [PATCH 1/5] Hide sold out grouped product options on grouped PDP. --- ...uctCustomStockWithOneOptionSoldOutTest.xml | 111 ++++++++++++++++++ .../Grouped/AdaptIsSalableOptionPlugin.php | 78 ++++++++++++ InventoryGroupedProduct/composer.json | 45 +++---- InventoryGroupedProduct/etc/di.xml | 3 + ...VisibleOnGroupedProductPageActionGroup.xml | 20 ++++ 5 files changed, 236 insertions(+), 21 deletions(-) create mode 100644 InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml create mode 100644 InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php create mode 100644 InventoryGroupedProductAdminUi/Test/Mftf/ActionGroup/StorefrontAssertLinkIsNotVisibleOnGroupedProductPageActionGroup.xml diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml new file mode 100644 index 000000000000..1919994cb2c3 --- /dev/null +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml @@ -0,0 +1,111 @@ + + + + + + + + + <description value="Verify totally sold out grouped product option on custom stock is not visible on storefront."/> + <testCaseId value="https://studio.cucumber.io/projects/69435/test-plan/folders/912250/scenarios/4747577"/> + <severity value="CRITICAL"/> + <group value="msi"/> + <group value="multi_mode"/> + </annotations> + + <before> + <!--Create test data.--> + <createData entity="FullSource1" stepKey="source"/> + <createData entity="BasicMsiStockWithMainWebsite1" stepKey="stock"/> + <createData entity="SourceStockLinked1" stepKey="linkSourceStock"> + <requiredEntity createDataKey="stock"/> + <requiredEntity createDataKey="source"/> + </createData> + <createData entity="ApiGroupedProduct" stepKey="groupedProduct"/> + <createData entity="ApiProductWithDescription" stepKey="product1"/> + <createData entity="ApiProductWithDescription" stepKey="product2"/> + <createData entity="OneSimpleProductLink" stepKey="addProductOne"> + <requiredEntity createDataKey="groupedProduct"/> + <requiredEntity createDataKey="product1"/> + </createData> + <updateData entity="OneMoreSimpleProductLink" createDataKey="addProductOne" stepKey="addProductTwo"> + <requiredEntity createDataKey="groupedProduct"/> + <requiredEntity createDataKey="product2"/> + </updateData> + <createData entity="MsiCustomer1" stepKey="customer"/> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + <!--Assign sources to product1.--> + <actionGroup ref="NavigateToCreatedProductEditPageActionGroup" stepKey="navigateToSimpleProduct1"> + <argument name="product" value="$product1$"/> + </actionGroup> + <actionGroup ref="UnassignSourceFromProductActionGroup" stepKey="unassignDefaultSourceFromProduct1"> + <argument name="sourceCode" value="{{_defaultSource.name}}"/> + </actionGroup> + <actionGroup ref="AdminAssignSourceToProductAndSetSourceQuantityActionGroup" stepKey="assignSourceToProduct1"> + <argument name="sourceCode" value="$source.source[source_code]$"/> + <argument name="sourceQty" value="{{minimalProductQty.value}}"/> + </actionGroup> + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct1"/> + <!--Assign sources to product2.--> + <actionGroup ref="NavigateToCreatedProductEditPageActionGroup" stepKey="navigateToSimpleProduct2"> + <argument name="product" value="$product2$"/> + </actionGroup> + <actionGroup ref="UnassignSourceFromProductActionGroup" stepKey="unassignDefaultSourceFromProduct2"> + <argument name="sourceCode" value="{{_defaultSource.name}}"/> + </actionGroup> + <actionGroup ref="AdminAssignSourceToProductAndSetSourceQuantityActionGroup" stepKey="assignSourceToProduct2"> + <argument name="sourceCode" value="$source.source[source_code]$"/> + </actionGroup> + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct2"/> + </before> + <after> + <deleteData createDataKey="customer" stepKey="deleteCustomer"/> + <deleteData createDataKey="groupedProduct" stepKey="deleteGroupedProduct"/> + <deleteData createDataKey="product1" stepKey="deleteSimpleProduct1"/> + <deleteData createDataKey="product2" stepKey="deleteSimpleProduct2"/> + <!--Assign Default Stock to Default Website.--> + <actionGroup ref="AssignWebsiteToStockActionGroup" stepKey="assignMainWebsiteToDefaultStock"> + <argument name="stockName" value="{{_defaultStock.name}}"/> + <argument name="websiteName" value="{{_defaultWebsite.name}}"/> + </actionGroup> + <!--Disable created sources.--> + <actionGroup ref="DisableAllSourcesActionGroup" stepKey="disableSource"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutOfAdmin"/> + <deleteData createDataKey="stock" stepKey="deleteStock"/> + </after> + + <!--Login To storefront as Customer--> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="loginToStorefront"> + <argument name="Customer" value="$$customer$$"/> + </actionGroup> + <!--Add grouped product to cart.--> + <actionGroup ref="StorefrontOpenProductEntityPageActionGroup" stepKey="navigateToGroupedProductPDP"> + <argument name="product" value="$groupedProduct$"/> + </actionGroup> + <actionGroup ref="StorefrontAddGroupedProductWithTwoLinksToCartActionGroup" stepKey="addGroupedProductToCart"> + <argument name="product" value="$groupedProduct$"/> + <argument name="linkedProduct1Name" value="$product1.name$"/> + <argument name="linkedProduct2Name" value="$product2.name$"/> + </actionGroup> + <!--Place order.--> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="navigateToCheckoutPage"/> + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNextButton"/> + <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> + <magentoCLI command="cache:flush" stepKey="cleanCache"/> + <!--Verify grouped product PDP.--> + <actionGroup ref="StorefrontOpenProductEntityPageActionGroup" stepKey="navigateToGroupedProductPDPAfterOrderPlacement"> + <argument name="product" value="$groupedProduct$"/> + </actionGroup> + <actionGroup ref="StorefrontAssertLinkIsNotVisibleOnGroupedProductPageActionGroup" stepKey="verifyFirstOptionIsNotPresentedOnPage"> + <argument name="productName" value="$product1.name$"/> + </actionGroup> + <actionGroup ref="AssertLinkPresenceOnGroupedProductPage" stepKey="verifySecondOptionIsStillPresentedOnPage"> + <argument name="productName" value="$product2.name$"/> + </actionGroup> + </test> +</tests> diff --git a/InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php b/InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php new file mode 100644 index 000000000000..78e818040245 --- /dev/null +++ b/InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +declare(strict_types=1); + +namespace Magento\InventoryGroupedProduct\Plugin\GroupedProduct\Model\Product\Type\Grouped; + +use Magento\Catalog\Model\ResourceModel\Product\Link\Product\Collection; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\GroupedProduct\Model\Product\Type\Grouped; +use Magento\InventorySalesApi\Api\AreProductsSalableInterface; +use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; +use Magento\InventorySalesApi\Api\StockResolverInterface; +use Magento\Store\Model\StoreManagerInterface; + +/** + * Filter only salable grouped options plugin. + */ +class AdaptIsSalableOptionPlugin +{ + /** + * @var AreProductsSalableInterface + */ + private $areProductsSalable; + + /** + * @var StoreManagerInterface + */ + private $storeManager; + + /** + * @var StockResolverInterface + */ + private $stockResolver; + + /** + * @param AreProductsSalableInterface $areProductsSalable + * @param StockResolverInterface $stockResolver + * @param StoreManagerInterface $storeManager + */ + public function __construct( + AreProductsSalableInterface $areProductsSalable, + StockResolverInterface $stockResolver, + StoreManagerInterface $storeManager + ) { + $this->areProductsSalable = $areProductsSalable; + $this->storeManager = $storeManager; + $this->stockResolver = $stockResolver; + } + + /** + * Filter salable grouped options. + * + * @param Grouped $subject + * @param Collection $result + * @return Collection + * @throws NoSuchEntityException in case there is no stock connected to given website. + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetAssociatedProductCollection(Grouped $subject, Collection $result): Collection + { + $website = $this->storeManager->getStore($result->getStoreId())->getWebsite(); + $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()); + $skus = array_column($result->getData(), 'sku'); + $areProductsSalable = $this->areProductsSalable->execute($skus, $stock->getStockId()); + $sksToInclude = []; + foreach ($areProductsSalable as $salableResult) { + if ($salableResult->isSalable()) { + $sksToInclude[] = $salableResult->getSku(); + } + } + $result->addAttributeToFilter('sku', ['in' => $sksToInclude]); + + return $result; + } +} diff --git a/InventoryGroupedProduct/composer.json b/InventoryGroupedProduct/composer.json index 341cecef5f1a..99b777842d13 100644 --- a/InventoryGroupedProduct/composer.json +++ b/InventoryGroupedProduct/composer.json @@ -1,25 +1,28 @@ { - "name": "magento/module-inventory-grouped-product", - "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-grouped-product": "*" - }, - "suggest": { - "magento/module-inventory-configuration-api": "*" - }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "autoload": { - "files": [ - "registration.php" + "name": "magento/module-inventory-grouped-product", + "description": "N/A", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "*", + "magento/module-catalog": "*", + "magento/module-grouped-product": "*", + "magento/module-inventory-sales-api": "*", + "magento/module-store": "*" + }, + "suggest": { + "magento/module-inventory-configuration-api": "*" + }, + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" ], - "psr-4": { - "Magento\\InventoryGroupedProduct\\": "" + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\InventoryGroupedProduct\\": "" + } } - } } diff --git a/InventoryGroupedProduct/etc/di.xml b/InventoryGroupedProduct/etc/di.xml index 76b925b8b2bf..04c475c07fd8 100644 --- a/InventoryGroupedProduct/etc/di.xml +++ b/InventoryGroupedProduct/etc/di.xml @@ -10,4 +10,7 @@ <plugin name="disable_grouped_type" type="Magento\InventoryGroupedProduct\Plugin\InventoryConfigurationApi\IsSourceItemManagementAllowedForProductType\DisableGroupedTypePlugin"/> </type> + <type name="Magento\GroupedProduct\Model\Product\Type\Grouped"> + <plugin name="adapt_is_salable_option" type="Magento\InventoryGroupedProduct\Plugin\GroupedProduct\Model\Product\Type\Grouped\AdaptIsSalableOptionPlugin"/> + </type> </config> diff --git a/InventoryGroupedProductAdminUi/Test/Mftf/ActionGroup/StorefrontAssertLinkIsNotVisibleOnGroupedProductPageActionGroup.xml b/InventoryGroupedProductAdminUi/Test/Mftf/ActionGroup/StorefrontAssertLinkIsNotVisibleOnGroupedProductPageActionGroup.xml new file mode 100644 index 000000000000..8c39a149eb9d --- /dev/null +++ b/InventoryGroupedProductAdminUi/Test/Mftf/ActionGroup/StorefrontAssertLinkIsNotVisibleOnGroupedProductPageActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontAssertLinkIsNotVisibleOnGroupedProductPageActionGroup"> + <annotations> + <description>Validates that the provided Product Name is not presented on a Storefront Grouped Product page.</description> + </annotations> + <arguments> + <argument name="productName" type="string"/> + </arguments> + + <dontSee selector="{{StorefrontProductInfoMainSection.groupedProductsTable}}" userInput="{{productName}}" stepKey="seeFirstStagedGroupedProduct"/> + </actionGroup> +</actionGroups> From f9ea14e3f885995ed9a871c8896beb226f0d5414 Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Fri, 22 May 2020 14:22:28 +0300 Subject: [PATCH 2/5] Fix tests. --- InventoryGroupedProduct/etc/di.xml | 3 --- InventoryGroupedProduct/etc/frontend/di.xml | 12 ++++++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 InventoryGroupedProduct/etc/frontend/di.xml diff --git a/InventoryGroupedProduct/etc/di.xml b/InventoryGroupedProduct/etc/di.xml index 04c475c07fd8..76b925b8b2bf 100644 --- a/InventoryGroupedProduct/etc/di.xml +++ b/InventoryGroupedProduct/etc/di.xml @@ -10,7 +10,4 @@ <plugin name="disable_grouped_type" type="Magento\InventoryGroupedProduct\Plugin\InventoryConfigurationApi\IsSourceItemManagementAllowedForProductType\DisableGroupedTypePlugin"/> </type> - <type name="Magento\GroupedProduct\Model\Product\Type\Grouped"> - <plugin name="adapt_is_salable_option" type="Magento\InventoryGroupedProduct\Plugin\GroupedProduct\Model\Product\Type\Grouped\AdaptIsSalableOptionPlugin"/> - </type> </config> diff --git a/InventoryGroupedProduct/etc/frontend/di.xml b/InventoryGroupedProduct/etc/frontend/di.xml new file mode 100644 index 000000000000..2ca4c5b05e17 --- /dev/null +++ b/InventoryGroupedProduct/etc/frontend/di.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\GroupedProduct\Model\Product\Type\Grouped"> + <plugin name="adapt_is_salable_option" type="Magento\InventoryGroupedProduct\Plugin\GroupedProduct\Model\Product\Type\Grouped\AdaptIsSalableOptionPlugin"/> + </type> +</config> From b84f4ba92ff5956a24cbd0bd2d0b4806cdec97c2 Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Wed, 10 Jun 2020 13:50:08 +0300 Subject: [PATCH 3/5] Add is "show out of stock" verification. --- .../Type/Grouped/AdaptIsSalableOptionPlugin.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php b/InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php index 78e818040245..23f9c6ecb6ad 100644 --- a/InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php +++ b/InventoryGroupedProduct/Plugin/GroupedProduct/Model/Product/Type/Grouped/AdaptIsSalableOptionPlugin.php @@ -8,6 +8,7 @@ namespace Magento\InventoryGroupedProduct\Plugin\GroupedProduct\Model\Product\Type\Grouped; use Magento\Catalog\Model\ResourceModel\Product\Link\Product\Collection; +use Magento\CatalogInventory\Api\StockConfigurationInterface; use Magento\Framework\Exception\NoSuchEntityException; use Magento\GroupedProduct\Model\Product\Type\Grouped; use Magento\InventorySalesApi\Api\AreProductsSalableInterface; @@ -35,19 +36,27 @@ class AdaptIsSalableOptionPlugin */ private $stockResolver; + /** + * @var StockConfigurationInterface + */ + private $stockConfiguration; + /** * @param AreProductsSalableInterface $areProductsSalable * @param StockResolverInterface $stockResolver * @param StoreManagerInterface $storeManager + * @param StockConfigurationInterface $stockConfiguration */ public function __construct( AreProductsSalableInterface $areProductsSalable, StockResolverInterface $stockResolver, - StoreManagerInterface $storeManager + StoreManagerInterface $storeManager, + StockConfigurationInterface $stockConfiguration ) { $this->areProductsSalable = $areProductsSalable; $this->storeManager = $storeManager; $this->stockResolver = $stockResolver; + $this->stockConfiguration = $stockConfiguration; } /** @@ -61,6 +70,9 @@ public function __construct( */ public function afterGetAssociatedProductCollection(Grouped $subject, Collection $result): Collection { + if ($this->stockConfiguration->isShowOutOfStock()) { + return $result; + } $website = $this->storeManager->getStore($result->getStoreId())->getWebsite(); $stock = $this->stockResolver->execute(SalesChannelInterface::TYPE_WEBSITE, $website->getCode()); $skus = array_column($result->getData(), 'sku'); From ad12c9f71bc2a21bcc13b9c9a2717913a87c0408 Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Wed, 10 Jun 2020 17:45:46 +0300 Subject: [PATCH 4/5] Fix tests. --- ...ntGroupedProductCustomStockWithOneOptionSoldOutTest.xml | 7 ++++++- InventoryGroupedProduct/composer.json | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml index 1919994cb2c3..1f8e9fe62690 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontGroupedProductCustomStockWithOneOptionSoldOutTest.xml @@ -96,7 +96,12 @@ <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="navigateToCheckoutPage"/> <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNextButton"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> - <magentoCLI command="cache:flush" stepKey="cleanCache"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber22}}" stepKey="orderNumber"/> + <!--Create Shipment--> + <actionGroup ref="OpenOrderByIdActionGroup" stepKey="openOrder"> + <argument name="orderId" value="{$orderNumber}"/> + </actionGroup> + <actionGroup ref="AdminShipThePendingOrderActionGroup" stepKey="shipOrder"/> <!--Verify grouped product PDP.--> <actionGroup ref="StorefrontOpenProductEntityPageActionGroup" stepKey="navigateToGroupedProductPDPAfterOrderPlacement"> <argument name="product" value="$groupedProduct$"/> diff --git a/InventoryGroupedProduct/composer.json b/InventoryGroupedProduct/composer.json index 99b777842d13..c76426e03304 100644 --- a/InventoryGroupedProduct/composer.json +++ b/InventoryGroupedProduct/composer.json @@ -5,6 +5,7 @@ "php": "~7.3.0||~7.4.0", "magento/framework": "*", "magento/module-catalog": "*", + "magento/module-catalog-inventory": "*", "magento/module-grouped-product": "*", "magento/module-inventory-sales-api": "*", "magento/module-store": "*" From 79ea43ce6dfa6cef3678c40d187ab62f1936b414 Mon Sep 17 00:00:00 2001 From: nmalevanec <mikola.malevanec@transoftgroup.com> Date: Mon, 15 Jun 2020 13:04:24 +0300 Subject: [PATCH 5/5] Fix test. --- ...ConfigurableProductAdditionalStockTest.xml | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml index 5579a169c3a9..850cc7bea066 100644 --- a/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml @@ -21,63 +21,70 @@ <before> <!--Create additional source and stock.--> - <createData entity="_minimalSource" stepKey="additionalSource" after="createProduct"/> - <createData entity="BasicMsiStockWithMainWebsite1" stepKey="additionalStock" after="additionalSource"/> + <createData entity="_minimalSource" stepKey="source" after="createProduct"/> + <createData entity="BasicMsiStockWithMainWebsite1" stepKey="stock" after="source"/> <!--Link additional source with stock.--> - <createData entity="SourceStockLinked1" stepKey="stockSourceLink" after="additionalStock"> - <requiredEntity createDataKey="additionalStock"/> - <requiredEntity createDataKey="additionalSource"/> + <createData entity="SourceStockLinked1" stepKey="stockSourceLink" after="stock"> + <requiredEntity createDataKey="stock"/> + <requiredEntity createDataKey="source"/> </createData> <!--Replace simple product with configurable.--> <remove keyForRemoval="createProduct"/> - <createData entity="ConfigurableMsiProduct" stepKey="createProduct"/> - <amOnPage url="{{AdminProductEditPage.url($$createProduct.id$$)}}" stepKey="openConfigurableProductEditPage" after="loginAsAdmin"/> - <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickOnTheCreateConfigurationsButton" after="openConfigurableProductEditPage"/> - <waitForElementVisible selector="{{AdminConfigurableProductSelectAttributesSlideOut.grid}}" time="30" stepKey="waitForGridPresents" after="clickOnTheCreateConfigurationsButton"/> - <click selector="{{AdminGridRow.checkboxByValue('color')}}" stepKey="selectColorAttribute" after="waitForGridPresents"/> - <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="navigateToSecondStep" after="selectColorAttribute"/> - <click selector="{{AdminCreateProductConfigurationsPanel.createNewValue}}" stepKey="addNewColorWhite" after="navigateToSecondStep"/> - <fillField userInput="{{colorProductAttribute1.name}}" selector="{{AdminCreateProductConfigurationsPanel.attributeName}}" stepKey="setNameWhite" after="addNewColorWhite"/> - <click selector="{{AdminCreateProductConfigurationsPanel.saveAttribute}}" stepKey="saveWhiteColor" after="setNameWhite"/> - <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="navigateToThirdStep" after="saveWhiteColor"/> - <click selector="{{AdminCreateProductConfigurationsPanel.applySingleQuantityToEachSkus}}" stepKey="clickOnApplySingleQuantityToEachSku" after="navigateToThirdStep"/> - <click selector="{{AdminConfigurableProductAssignSourcesSlideOut.assignSources}}" stepKey="openSelectSourcesModalWindow" after="clickOnApplySingleQuantityToEachSku"/> - <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearSourcesFilter" after="openSelectSourcesModalWindow"/> - <actionGroup ref="SearchAdminDataGridByKeywordActionGroup" stepKey="searchCustomSourceByNameForAssignment" after="clearSourcesFilter"> - <argument name="keyword" value="$$additionalSource.source[name]$$"/> + <createData entity="ApiConfigurableProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="productAttributeWithTwoOptions" stepKey="configurableProductAttribute" after="createProduct"/> + <createData entity="productAttributeOption1" stepKey="configurableProductAttributeOption" after="configurableProductAttribute"> + <requiredEntity createDataKey="configurableProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet" after="configurableProductAttributeOption"> + <requiredEntity createDataKey="configurableProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption" after="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="configurableProductAttribute"/> + </getData> + <createData entity="ApiSimpleOne" stepKey="configurableChildProduct" after="getConfigAttributeOption"> + <requiredEntity createDataKey="configurableProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption"/> + </createData> + <createData entity="ConfigurableProductOneOption" stepKey="configurableProductOption" after="configurableChildProduct"> + <requiredEntity createDataKey="createProduct"/> + <requiredEntity createDataKey="configurableProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="configurableProductAddChild" after="configurableProductOption"> + <requiredEntity createDataKey="createProduct"/> + <requiredEntity createDataKey="configurableChildProduct"/> + </createData> + <!--Assign additional source to configurable product.--> + <amOnPage url="{{AdminProductEditPage.url($configurableChildProduct.id$)}}" stepKey="openProductEditPage" after="loginAsAdmin"/> + <actionGroup ref="UnassignSourceFromProductActionGroup" stepKey="unassignDefaultSourceFromProduct" after="openProductEditPage"> + <argument name="sourceCode" value="{{_defaultSource.name}}"/> </actionGroup> - <click selector="{{AdminGridRow.checkboxByValue($$additionalSource.source[name]$$)}}" stepKey="selectCustomSource" after="searchCustomSourceByNameForAssignment"/> - <click selector="{{AdminConfigurableProductAssignSourcesSlideOut.done}}" stepKey="daneAssignSources" after="selectCustomSource"/> - <fillField selector="{{AdminConfigurableProductAssignSourcesSlideOut.quantityPerSourceForMultiMode}}" userInput="100" stepKey="fillQuantityForCustomSource" after="daneAssignSources"/> - <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="navigateToFourthStep" after="fillQuantityForCustomSource"/> - <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="doneGeneratingConfigurableVariations" after="navigateToFourthStep"/> - <click selector="{{AdminProductFormSection.save}}" stepKey="saveConfigurableProduct" after="doneGeneratingConfigurableVariations"/> - <conditionalClick selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" dependentSelector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" visible="true" stepKey="confirmDefaultAttributeSetForConfigurableProduct" after="saveConfigurableProduct"/> - <!--Set configurable product stock status.--> - <selectOption selector="{{AdminProductFormSection.productStockStatus}}" userInput="In Stock" stepKey="setProductStockStatus" after="confirmDefaultAttributeSetForConfigurableProduct"/> - <!--Assign configurable product to category.--> - <actionGroup ref="AdminAssignCategoryToProductAndSaveActionGroup" stepKey="assignCategoryToConfigurableProduct" after="setProductStockStatus"> - <argument name="categoryName" value="$$createCategory.name$$"/> + <actionGroup ref="AdminAssignSourceToProductAndSetSourceQuantityActionGroup" stepKey="assignSourceToProduct" after="unassignDefaultSourceFromProduct"> + <argument name="sourceCode" value="$source.source[source_code]$"/> </actionGroup> + <actionGroup ref="SaveProductFormActionGroup" stepKey="saveProduct" after="assignSourceToProduct"/> </before> <after> + <!--Clean up test data.--> + <deleteData createDataKey="configurableChildProduct" stepKey="deleteConfigurableProductVariation" after="deleteCategory"/> + <deleteData createDataKey="configurableProductAttribute" stepKey="deleteConfigurableProductAttribute" after="deleteConfigurableProductVariation"/> <!--Assign Default Stock to Default Website.--> - <actionGroup ref="AssignWebsiteToStockActionGroup" stepKey="assignMainWebsiteToDefaultStock" after="deleteCategory"> + <actionGroup ref="AssignWebsiteToStockActionGroup" stepKey="assignMainWebsiteToDefaultStock" after="deleteConfigurableProductAttribute"> <argument name="stockName" value="{{_defaultStock.name}}"/> <argument name="websiteName" value="{{_defaultWebsite.name}}"/> </actionGroup> <!--Disable additional source.--> - <actionGroup ref="DisableSourceActionGroup" stepKey="disableCreatedSource" before="assignMainWebsiteToDefaultStock"> - <argument name="sourceCode" value="$$additionalSource.source[source_code]$$"/> - </actionGroup> + <actionGroup ref="DisableAllSourcesActionGroup" stepKey="disableCreatedSource" before="assignMainWebsiteToDefaultStock"/> <!--Delete stock.--> - <deleteData createDataKey="additionalStock" stepKey="deleteStock" after="assignMainWebsiteToDefaultStock"/> + <deleteData createDataKey="stock" stepKey="deleteStock" after="assignMainWebsiteToDefaultStock"/> </after> <!--Verify configurable product prices.--> <remove keyForRemoval="seeDiscountedPrice1"/> - <see selector="{{StorefrontCategoryProductSection.ProductInfoByNumber('1')}}" userInput="As low as $90.00" stepKey="seeDiscountedPrice1" after="seeProduct1"/> + <see selector="{{StorefrontCategoryProductSection.ProductInfoByNumber('1')}}" userInput="As low as $110.70" stepKey="seeDiscountedPrice1" after="seeProduct1"/> <remove keyForRemoval="seeDiscountedPrice2"/> - <see selector="{{StorefrontCategoryProductSection.ProductInfoByNumber('1')}}" userInput="As low as $100.00" stepKey="seeDiscountedPrice2" after="seeProduct2"/> + <see selector="{{StorefrontCategoryProductSection.ProductInfoByNumber('1')}}" userInput="As low as ${{ApiSimpleOne.price}}" stepKey="seeDiscountedPrice2" after="seeProduct2"/> </test> </tests>