diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/ActionGroup/AdminOnProductEditPageAssignSourceToProductActionGroup.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/ActionGroup/AdminOnProductEditPageAssignSourceToProductActionGroup.xml index 794422df2f28..1d91a1259588 100644 --- a/app/code/Magento/InventoryAdminUi/Test/Mftf/ActionGroup/AdminOnProductEditPageAssignSourceToProductActionGroup.xml +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/ActionGroup/AdminOnProductEditPageAssignSourceToProductActionGroup.xml @@ -15,13 +15,13 @@ - + - + - + diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForBundleProductInSingleStockModeTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForBundleProductInSingleStockModeTest.xml new file mode 100644 index 000000000000..20d3c5200e29 --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForBundleProductInSingleStockModeTest.xml @@ -0,0 +1,72 @@ + + + + + + + + + <description value="Quick Catalog Search for Bundle Product on Single stock mode"/> + <testCaseId value="MSI-1812"/> + <severity value="AVERAGE"/> + <group value="msi"/> + <group value="single_mode"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="category"/> + <createData entity="SimpleProduct" stepKey="simpleProduct"> + <requiredEntity createDataKey="category"/> + </createData> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + </after> + + <comment userInput="Create bundle product." stepKey="createBundleProductComment"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPageBundle"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateBundleProduct"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + <actionGroup ref="fillProductNameAndSkuInProductForm" stepKey="fillBundleProductNameAndSku"> + <argument name="product" value="BundleProduct"/> + </actionGroup> + + <comment userInput="Add bundle item." stepKey="addBundleItemComment"/> + <conditionalClick selector="{{AdminProductFormBundleSection.bundleItemsToggle}}" dependentSelector="{{AdminProductFormBundleSection.bundleItemsToggle}}" visible="false" stepKey="conditionallyOpenSectionBundleItems"/> + <click selector="{{AdminProductFormBundleSection.addOption}}" stepKey="clickAddOption"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXTitle('0')}}" userInput="{{BundleProduct.optionTitle1}}" stepKey="fillOptionTitle"/> + <selectOption selector="{{AdminProductFormBundleSection.bundleOptionXInputType('0')}}" userInput="{{BundleProduct.optionInputType1}}" stepKey="selectInputType"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <click selector="{{AdminProductFormBundleSection.addProductsToOption}}" stepKey="clickAddProductsToOption"/> + <waitForPageLoad stepKey="waitForPageLoad4"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterBundleProductOptions"> + <argument name="product" value="$$simpleProduct$$"/> + </actionGroup> + <checkOption selector="{{AdminAddProductsToOptionPanel.firstCheckbox}}" stepKey="selectFirstGridRow"/> + <click selector="{{AdminAddProductsToOptionPanel.addSelectedProducts}}" stepKey="clickAddSelectedBundleProducts"/> + <fillField selector="{{AdminProductFormBundleSection.bundleOptionXProductYQuantity('0', '0')}}" userInput="5" stepKey="fillProductDefaultQty"/> + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseCreatedBundleProduct"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad5"/> + + <fillField userInput="{{BundleProduct.name}}" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad6"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '{{BundleProduct.name}}'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '{{BundleProduct.name}}'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="{{BundleProduct.name}}" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForConfigurableProductOnTestStockTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForConfigurableProductOnTestStockTest.xml new file mode 100644 index 000000000000..d96e8f1d7da9 --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForConfigurableProductOnTestStockTest.xml @@ -0,0 +1,116 @@ +<?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="AdminCatalogQuickSearchForConfigurableProductOnTestStockTest"> + <annotations> + <stories value="Catalog Quick Search"/> + <title value="Quick Catalog Search for Configurable Product on Test stock"/> + <description value="Quick Catalog Search for Configurable Product on Test stock"/> + <testCaseId value="MSI-1788"/> + <severity value="CRITICAL"/> + <group value="msi"/> + <group value="multi_mode"/> + </annotations> + + <before> + <createData entity="FullSource1" stepKey="createSource1"/> + <createData entity="BasicMsiStockWithMainWebsite1" stepKey="createStock1"/> + <createData entity="SourceStockLinked1" stepKey="stockSourceLink1"> + <requiredEntity createDataKey="createStock1"/> + <requiredEntity createDataKey="createSource1"/> + </createData> + + <createData entity="SimpleSubCategory" stepKey="createCategory1"/> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + </after> + + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToAdminProductGrid"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickOnAddProductToggle"/> + <click selector="{{AdminProductGridActionSection.addTypeProduct('configurable')}}" + stepKey="addConfigurableProduct"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + + <fillField userInput="{{ConfigurableMsiProduct.name}}" selector="{{AdminProductFormSection.productName}}" + stepKey="fillProductName"/> + <fillField userInput="{{ConfigurableMsiProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" + stepKey="fillProductPrice"/> + <fillField userInput="{{ConfigurableMsiProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" + stepKey="fillProductSku"/> + <fillField userInput="{{ConfigurableMsiProduct.quantity}}" + selector="{{AdminConfigurableProductFormSection.productQuantity}}" + stepKey="fillProductQuantity"/> + <fillField userInput="{{ConfigurableMsiProduct.weight}}" + selector="{{AdminConfigurableProductFormSection.productWeight}}" stepKey="fillProductWeight"/> + + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" + parameterArray="[$$createCategory1.name$$]" stepKey="searchAndSelectCategory"/> + <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" + stepKey="clickOnTheCreateConfigurationsButton"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad3"/> + + <click selector="{{AdminGridRow.checkboxByValue('color')}}" stepKey="selectColorAttribute"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="navigateToSecondStep"/> + + <click selector="{{AdminCreateProductConfigurationsPanel.createNewValue}}" stepKey="addNewColorWhite"/> + <fillField userInput="{{colorProductAttribute1.name}}" + selector="{{AdminCreateProductConfigurationsPanel.attributeName}}" stepKey="setNameWhite"/> + <click selector="{{AdminCreateProductConfigurationsPanel.saveAttribute}}" stepKey="saveWhiteColor"/> + + <click selector="{{AdminCreateProductConfigurationsPanel.createNewValue}}" stepKey="addNewColorRed"/> + <fillField userInput="{{colorProductAttribute2.name}}" + selector="{{AdminCreateProductConfigurationsPanel.attributeName}}" stepKey="setNameRed"/> + <click selector="{{AdminCreateProductConfigurationsPanel.saveAttribute}}" stepKey="saveRedColor"/> + + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="navigateToThirdStep"/> + + <click selector="{{AdminCreateProductConfigurationsPanel.applySingleQuantityToEachSkus}}" + stepKey="clickOnApplySingleQuantityToEachSku"/> + + <click selector="{{AdminConfigurableProductAssignSourcesSlideOut.assignSources}}" + stepKey="openSelectSourcesModalWindow1"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" + dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" + stepKey="clearSourcesFilter"/> + <actionGroup ref="searchAdminDataGridByKeyword" stepKey="searchCustomSourceByNameForAssignment"> + <argument name="keyword" value="$$createSource1.source[name]$$"/> + </actionGroup> + <click selector="{{AdminGridRow.checkboxByValue($$createSource1.source[name]$$)}}" + stepKey="selectCustomSource1"/> + <click selector="{{AdminConfigurableProductAssignSourcesSlideOut.done}}" stepKey="doneAssignSources1"/> + <fillField selector="{{AdminConfigurableProductAssignSourcesSlideOut.quantityPerSource('0')}}" + userInput="100" stepKey="fillQuantityForCustomSource1"/> + + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="navigateToFourthStep"/> + <click selector="{{AdminCreateProductConfigurationsPanel.next}}" + stepKey="doneGeneratingConfigurableVariations"/> + + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveConfigurableProduct"/> + <conditionalClick selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" + dependentSelector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" visible="true" + stepKey="confirmDefaultAttributeSetForConfigurableProduct"/> + <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="checkProductSavedMessage"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad4"/> + + <fillField userInput="{{ConfigurableMsiProduct.name}}" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad5"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '{{ConfigurableMsiProduct.name}}'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '{{ConfigurableMsiProduct.name}}'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="{{ConfigurableMsiProduct.name}}" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForDownloadableProductInSingleStockModeTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForDownloadableProductInSingleStockModeTest.xml new file mode 100644 index 000000000000..1b365261c2c7 --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForDownloadableProductInSingleStockModeTest.xml @@ -0,0 +1,77 @@ +<?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="AdminCatalogQuickSearchForDownloadableProductInSingleStockModeTest"> + <annotations> + <stories value="Catalog Quick Search"/> + <title value="Quick Catalog Search for Downloadable Product on Single stock"/> + <description value="Quick Catalog Search for Downloadable Product on Single stock"/> + <testCaseId value="MSI-1814"/> + <severity value="MAJOR"/> + <group value="msi"/> + <group value="single_mode"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="simpleCategory1"/> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + </after> + + <comment userInput="Create downloadable product with category and link." stepKey="createDownloadableProductComment"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageAdd"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProductPage"> + <argument name="product" value="DownloadableProduct"/> + </actionGroup> + <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{DownloadableProduct.name}}" stepKey="fillProductSku"/> + <fillField selector="{{AdminProductFormSection.productSku}}" userInput="{{DownloadableProduct.sku}}" stepKey="fillProductName"/> + <fillField selector="{{AdminProductFormSection.productPrice}}" userInput="{{DownloadableProduct.price}}" stepKey="fillProductPrice"/> + + <comment userInput="Assign category to product." stepKey="assignCategoryComment"/> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$simpleCategory1.name$$]" requiredAction="true" stepKey="searchAndSelectCategory"/> + <click selector="{{AdminProductDownloadableSection.sectionHeader}}" stepKey="openDownloadableSection1"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <checkOption selector="{{AdminProductDownloadableSection.isDownloadableProduct}}" stepKey="checkIsDownloadable1"/> + <fillField userInput="{{downloadableData.link_title}}" selector="{{AdminProductDownloadableSection.linksTitleInput}}" stepKey="fillDownloadableLinkTitle1"/> + <checkOption selector="{{AdminProductDownloadableSection.isLinksPurchasedSeparately}}" stepKey="checkLinksPurchasedSeparately1"/> + <fillField userInput="{{downloadableData.sample_title}}" selector="{{AdminProductDownloadableSection.samplesTitleInput}}" stepKey="fillDownloadableSampleTitle1"/> + + <click selector="{{AdminProductDownloadableSection.linksAddLinkButton}}" stepKey="clickLinkAddLinkButton1"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <fillField userInput="{{downloadableLink.title}}" selector="{{AdminProductDownloadableSection.addLinkTitleInput('0')}}" stepKey="fillDownloadableLinkTitle2"/> + <fillField userInput="{{downloadableLink.price}}" selector="{{AdminProductDownloadableSection.addLinkPriceInput('0')}}" stepKey="fillDownloadableLinkPrice2"/> + <selectOption userInput="{{downloadableLink.file_type}}" selector="{{AdminProductDownloadableSection.addLinkFileTypeSelector('0')}}" stepKey="selectDownloadableLinkFileType2"/> + <selectOption userInput="{{downloadableLink.sample_type}}" selector="{{AdminProductDownloadableSection.addLinkSampleTypeSelector('0')}}" stepKey="selectDownloadableLinkSampleType2"/> + <selectOption userInput="{{downloadableLink.shareable}}" selector="{{AdminProductDownloadableSection.addLinkShareableSelector('0')}}" stepKey="selectDownloadableLinkShareable2"/> + <checkOption selector="{{AdminProductDownloadableSection.addLinkIsUnlimitedDownloads('0')}}" stepKey="checkDownloadableLinkUnlimited2"/> + <fillField userInput="{{downloadableLink.file}}" selector="{{AdminProductDownloadableSection.addLinkFileUrlInput('0')}}" stepKey="fillDownloadableLinkFileUrl2"/> + <attachFile userInput="{{downloadableLink.sample}}" selector="{{AdminProductDownloadableSection.addLinkSampleUploadFile('0')}}" stepKey="attachDownloadableLinkUploadSample2"/> + + <fillField selector="{{AdminProductFormSection.productQuantity}}" userInput="100" stepKey="fillProductQty1"/> + <selectOption selector="{{AdminProductFormSection.productStockStatus}}" userInput="In Stock" stepKey="selectStockStatus1"/> + + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseCreatedVirtualProduct"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad4"/> + + <fillField userInput="{{DownloadableProduct.name}}" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad5"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '{{DownloadableProduct.name}}'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '{{DownloadableProduct.name}}'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="{{DownloadableProduct.name}}" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForDownloadableProductOnTestStockTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForDownloadableProductOnTestStockTest.xml new file mode 100644 index 000000000000..fdba75c2eee8 --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForDownloadableProductOnTestStockTest.xml @@ -0,0 +1,88 @@ +<?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="AdminCatalogQuickSearchForDownloadableProductOnTestStockTest"> + <annotations> + <stories value="Catalog Quick Search"/> + <title value="Quick Catalog Search for Downloadable Product on Test stock"/> + <description value="Quick Catalog Search for Downloadable Product on Test stock"/> + <testCaseId value="MSI-1790"/> + <severity value="CRITICAL"/> + <group value="msi"/> + <group value="multi_mode"/> + </annotations> + + <before> + <createData entity="BasicMsiStockWithMainWebsite1" stepKey="createStock1"/> + <createData entity="FullSource1" stepKey="createSource1"/> + <createData entity="SourceStockLinked1" stepKey="linkSourceStock1"> + <requiredEntity createDataKey="createStock1"/> + <requiredEntity createDataKey="createSource1"/> + </createData> + + <createData entity="SimpleSubCategory" stepKey="simpleCategory1"/> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + </after> + + <comment userInput="Create downloadable product with category and link." stepKey="createDownloadableProductComment"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="adminProductIndexPageAdd"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProductPage"> + <argument name="product" value="DownloadableProduct"/> + </actionGroup> + <fillField selector="{{AdminProductFormSection.productName}}" userInput="{{DownloadableProduct.name}}" stepKey="fillProductSku"/> + <fillField selector="{{AdminProductFormSection.productSku}}" userInput="{{DownloadableProduct.sku}}" stepKey="fillProductName"/> + <fillField selector="{{AdminProductFormSection.productPrice}}" userInput="{{DownloadableProduct.price}}" stepKey="fillProductPrice"/> + + <comment userInput="Assign category to product." stepKey="assignCategoryComment"/> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$simpleCategory1.name$$]" requiredAction="true" stepKey="searchAndSelectCategory"/> + <click selector="{{AdminProductDownloadableSection.sectionHeader}}" stepKey="openDownloadableSection1"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> + <checkOption selector="{{AdminProductDownloadableSection.isDownloadableProduct}}" stepKey="checkIsDownloadable1"/> + <fillField userInput="{{downloadableData.link_title}}" selector="{{AdminProductDownloadableSection.linksTitleInput}}" stepKey="fillDownloadableLinkTitle1"/> + <checkOption selector="{{AdminProductDownloadableSection.isLinksPurchasedSeparately}}" stepKey="checkLinksPurchasedSeparately1"/> + <fillField userInput="{{downloadableData.sample_title}}" selector="{{AdminProductDownloadableSection.samplesTitleInput}}" stepKey="fillDownloadableSampleTitle1"/> + + <click selector="{{AdminProductDownloadableSection.linksAddLinkButton}}" stepKey="clickLinkAddLinkButton1"/> + <waitForPageLoad stepKey="waitForPageLoad4"/> + <fillField userInput="{{downloadableLink.title}}" selector="{{AdminProductDownloadableSection.addLinkTitleInput('0')}}" stepKey="fillDownloadableLinkTitle2"/> + <fillField userInput="{{downloadableLink.price}}" selector="{{AdminProductDownloadableSection.addLinkPriceInput('0')}}" stepKey="fillDownloadableLinkPrice2"/> + <selectOption userInput="{{downloadableLink.file_type}}" selector="{{AdminProductDownloadableSection.addLinkFileTypeSelector('0')}}" stepKey="selectDownloadableLinkFileType2"/> + <selectOption userInput="{{downloadableLink.sample_type}}" selector="{{AdminProductDownloadableSection.addLinkSampleTypeSelector('0')}}" stepKey="selectDownloadableLinkSampleType2"/> + <selectOption userInput="{{downloadableLink.shareable}}" selector="{{AdminProductDownloadableSection.addLinkShareableSelector('0')}}" stepKey="selectDownloadableLinkShareable2"/> + <checkOption selector="{{AdminProductDownloadableSection.addLinkIsUnlimitedDownloads('0')}}" stepKey="checkDownloadableLinkUnlimited2"/> + <fillField userInput="{{downloadableLink.file}}" selector="{{AdminProductDownloadableSection.addLinkFileUrlInput('0')}}" stepKey="fillDownloadableLinkFileUrl2"/> + <attachFile userInput="{{downloadableLink.sample}}" selector="{{AdminProductDownloadableSection.addLinkSampleUploadFile('0')}}" stepKey="attachDownloadableLinkUploadSample2"/> + + <scrollToTopOfPage stepKey="scrollToTopOfPage1"/> + <actionGroup ref="AdminOnProductEditPageAssignSourceToProduct" stepKey="AdminOnProductEditPageAssignSourceToProduct1"> + <argument name="filter_selector" value="AdminManageSourcesGridFilterControls.code"/> + <argument name="filter_value" value="$$createSource1.source[source_code]$$"/> + </actionGroup> + <fillField selector="{{AdminProductSourcesGrid.rowQty('0')}}" userInput="100" stepKey="fillSourceQuantityField"/> + + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseProduct"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad5"/> + + <fillField userInput="{{DownloadableProduct.name}}" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad6"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '{{DownloadableProduct.name}}'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '{{DownloadableProduct.name}}'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="{{DownloadableProduct.name}}" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForGroupedProductInSingleStockModeTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForGroupedProductInSingleStockModeTest.xml new file mode 100644 index 000000000000..ef52529f8c4b --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForGroupedProductInSingleStockModeTest.xml @@ -0,0 +1,91 @@ +<?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="AdminCatalogQuickSearchForGroupedProductInSingleStockModeTest"> + <annotations> + <stories value="Catalog Quick Search"/> + <title value="Quick Catalog Search for Grouped Product on Single stock mode"/> + <description value="Quick Catalog Search for Grouped Product on Single stock mode"/> + <testCaseId value="MSI-1815"/> + <severity value="MAJOR"/> + <group value="msi"/> + <group value="single_mode"/> + </annotations> + + <before> + <magentoCLI command="config:set cataloginventory/item_options/manage_stock 1" stepKey="magentoCLI1"/> + + <createData entity="SimpleSubCategory" stepKey="category"/> + <createData entity="VirtualProduct" stepKey="virtualProduct"/> + <createData entity="SimpleProduct" stepKey="simpleProduct"> + <requiredEntity createDataKey="category"/> + </createData> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <deleteData createDataKey="simpleProduct" stepKey="deleteSimpleProduct"/> + <deleteData createDataKey="virtualProduct" stepKey="deleteVirtualProduct"/> + </after> + + <comment userInput="Create grouped product." stepKey="createGroupedProductComment"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + <actionGroup ref="goToCreateProductPage" stepKey="goToCreateProduct"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <actionGroup ref="fillGroupedProductForm" stepKey="fillProductForm"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + + <comment userInput="Add simple and virtual products to grouped product." stepKey="assignSimpleAndVirtualToGroupedProductComment"/> + <scrollTo selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" x="0" y="-100" stepKey="scrollToGroupedSection"/> + <conditionalClick selector="{{AdminProductFormGroupedProductsSection.toggleGroupedProduct}}" dependentSelector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" visible="false" stepKey="openGroupedProductsSection"/> + <click selector="body" stepKey="clickBodyToCorrectFocusGrouped"/> + <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroupToAddSimpleProduct"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + <actionGroup ref="filterProductGridBySku2" stepKey="filterGroupedProductsToFindSimpleProduct"> + <argument name="sku" value="$$simpleProduct.sku$$"/> + </actionGroup> + <waitForPageLoad time="30" stepKey="waitForPageLoad3"/> + + <checkOption selector="{{AdminAddProductsToGroupPanel.nThCheckbox('0')}}" stepKey="selectSimpleProduct"/> + <click selector="{{AdminAddProductsToGroupPanel.addSelectedProducts}}" stepKey="addSimpleProduct"/> + <click selector="{{AdminProductFormGroupedProductsSection.addProductsToGroup}}" stepKey="clickAddProductsToGroupToAddVirtualProduct"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad4"/> + <actionGroup ref="filterProductGridBySku2" stepKey="filterGroupedProductsToFindVirtualProduct"> + <argument name="sku" value="$$virtualProduct.sku$$"/> + </actionGroup> + <waitForPageLoad time="30" stepKey="waitForPageLoad5"/> + <checkOption selector="{{AdminAddProductsToGroupPanel.nThCheckbox('0')}}" stepKey="selectVirtualProduct"/> + <click selector="{{AdminAddProductsToGroupPanel.addSelectedProducts}}" stepKey="addVirtualProduct"/> + + <scrollToTopOfPage stepKey="scrollToTopOfPage1"/> + <comment userInput="Assign category to product." stepKey="assignCategoryComment"/> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$category.name$$]" stepKey="searchAndSelectCategory"/> + + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseCreatedGroupedProduct"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad6"/> + + <fillField userInput="{{GroupedProduct.name}}" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad7"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '{{GroupedProduct.name}}'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '{{GroupedProduct.name}}'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="{{GroupedProduct.name}}" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForSimpleProductOnTestStockTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForSimpleProductOnTestStockTest.xml new file mode 100644 index 000000000000..03fff5285b26 --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForSimpleProductOnTestStockTest.xml @@ -0,0 +1,64 @@ +<?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="AdminCatalogQuickSearchForSimpleProductOnTestStockTest"> + <annotations> + <stories value="Catalog Quick Search"/> + <title value="Quick Catalog Search for Simple Product on Test stock"/> + <description value="Quick Catalog Search for Simple Product on Test stock"/> + <testCaseId value="MSI-1787"/> + <severity value="CRITICAL"/> + <group value="msi"/> + <group value="multi_mode"/> + </annotations> + + <before> + <createData entity="BasicMsiStockWithMainWebsite1" stepKey="createStock1"/> + <createData entity="FullSource1" stepKey="createSource1"/> + <createData entity="SourceStockLinked1" stepKey="linkSourceStock1"> + <requiredEntity createDataKey="createStock1"/> + <requiredEntity createDataKey="createSource1"/> + </createData> + + <createData entity="SimpleSubCategory" stepKey="simpleCategory1"/> + <createData entity="SimpleMsiProduct" stepKey="simpleProduct1"/> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + </after> + + <actionGroup ref="AdminGoToProductGridFilterResultsByInputEditProduct" stepKey="goToProductGridFilterResultsByInputEditProduct1"> + <argument name="filter_selector" value="AdminProductGridFilterSection.skuFilter"/> + <argument name="filter_value" value="$$simpleProduct1.product[sku]$$"/> + </actionGroup> + + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$simpleCategory1.name$$]" requiredAction="true" stepKey="searchAndSelectCategory1"/> + + <actionGroup ref="AssignSourceToProductActionGroup" stepKey="assignTestSourceToCreatedProduct1"> + <argument name="sourceCode" value="$$createSource1.source[source_code]$$"/> + </actionGroup> + <fillField selector="{{AdminProductSourcesGrid.rowQty('1')}}" userInput="100" stepKey="fillTestSourceQtyField1"/> + + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseCreatedVirtualProduct1"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + + <fillField userInput="$$simpleProduct1.product[name]$$" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '$$simpleProduct1.product[name]$$'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '$$simpleProduct1.product[name]$$'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="$$simpleProduct1.product[name]$$" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductInSingleStockModeTestst.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductInSingleStockModeTestst.xml new file mode 100644 index 000000000000..0c0c853da5de --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductInSingleStockModeTestst.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="AdminCatalogQuickSearchForVirtualProductInSingleStockModeTest"> + <annotations> + <stories value="Catalog Quick Search"/> + <title value="Quick Catalog Search for Virtual Product on Single stock"/> + <description value="Quick Catalog Search for Virtual Product on Single stock"/> + <testCaseId value="MSI-1312"/> + <severity value="MAJOR"/> + <group value="msi"/> + <group value="single_mode"/> + </annotations> + + <before> + <createData entity="SimpleSubCategory" stepKey="category"/> + <createData entity="Msi_US_Customer" stepKey="customer"/> + <createData entity="VirtualMsiProduct" stepKey="product"/> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + + <deleteData createDataKey="category" stepKey="deleteCategory"/> + <deleteData createDataKey="product" stepKey="deleteProduct"/> + <deleteData createDataKey="customer" stepKey="deleteCustomer"/> + </after> + + <comment userInput="Assign category to created virtual product." stepKey="assignCategoryToProductComment"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndexPageForEditProduct"/> + <actionGroup ref="AdminGridFilterSearchResultsByInput" stepKey="findSimpleProductBySku"> + <argument name="selector" value="AdminProductGridFilterSection.skuFilter"/> + <argument name="value" value="$$product.sku$$"/> + </actionGroup> + <click selector="{{AdminProductGridSection.productGridXRowYColumnButton('1', '2')}}" stepKey="openProductEditPage"/> + + <fillField selector="{{AdminProductFormSection.productQuantity}}" userInput="100" stepKey="fillProductQty1"/> + <selectOption selector="{{AdminProductFormSection.productStockStatus}}" userInput="In Stock" stepKey="selectStockStatus1"/> + + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$category.name$$]" requiredAction="true" stepKey="searchAndSelectCategory"/> + + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseCreatedVirtualProduct"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + + <fillField userInput="$$product.product[name]$$" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '$$product.product[name]$$'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '$$product.product[name]$$'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="$$product.product[name]$$" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductOnTestStockTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductOnTestStockTest.xml new file mode 100644 index 000000000000..137184e1086b --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductOnTestStockTest.xml @@ -0,0 +1,66 @@ +<?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="AdminCatalogQuickSearchForVirtualProductOnTestStockTest"> + <annotations> + <stories value="Catalog Quick Search"/> + <title value="Quick Catalog Search for Virtual Product on Test stock"/> + <description value="Quick Catalog Search for Virtual Product on Test stock"/> + <testCaseId value="MSI-1789"/> + <severity value="CRITICAL"/> + <group value="msi"/> + <group value="multi_mode"/> + </annotations> + + <before> + <createData entity="FullSource1" stepKey="createSource1"/> + <createData entity="BasicMsiStockWithMainWebsite1" stepKey="createStock1"/> + <createData entity="SourceStockLinked1" stepKey="stockSourceLink1"> + <requiredEntity createDataKey="createStock1"/> + <requiredEntity createDataKey="createSource1"/> + </createData> + + <createData entity="SimpleSubCategory" stepKey="createCategory1"/> + <createData entity="VirtualMsiProduct" stepKey="virtualProduct1"> + <requiredEntity createDataKey="createCategory1"/> + </createData> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin1"/> + </after> + + <actionGroup ref="AdminGoToProductGridFilterResultsByInputEditProduct" stepKey="goToProductGridFilterResultsByInputEditProduct1"> + <argument name="filter_selector" value="AdminProductGridFilterSection.skuFilter"/> + <argument name="filter_value" value="$$virtualProduct1.product[sku]$$"/> + </actionGroup> + + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createCategory1.name$$]" requiredAction="true" stepKey="searchAndSelectCategory1"/> + + <actionGroup ref="AssignSourceToProductActionGroup" stepKey="assignTestSourceToCreatedProduct1"> + <argument name="sourceCode" value="$$createSource1.source[source_code]$$"/> + </actionGroup> + <fillField selector="{{AdminProductSourcesGrid.rowQty('1')}}" userInput="100" stepKey="fillTestSourceQtyField1"/> + + <actionGroup ref="AdminFormSaveAndClose" stepKey="saveAndCloseCreatedVirtualProduct1"/> + + <amOnPage url="{{StorefrontHomePage.url}}" stepKey="goToHomePage1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + + <fillField userInput="$$virtualProduct1.product[name]$$" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillSearchBar1"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad2"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickSearchButton"/> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl1"/> + <seeInTitle userInput="Search results for: '$$virtualProduct1.product[name]$$'" stepKey="assertQuickSearchTitle1"/> + <see userInput="Search results for: '$$virtualProduct1.product[name]$$'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName1"/> + <see selector="{{CatalogSearchResultSection.productListBlock}}" userInput="$$virtualProduct1.product[name]$$" stepKey="verifyProductAppearedInSearchResults" /> + </test> +</tests> diff --git a/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCreateNewSourceAndCheckDisableSourceCodeTest.xml b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCreateNewSourceAndCheckDisableSourceCodeTest.xml new file mode 100644 index 000000000000..f811a15566ad --- /dev/null +++ b/app/code/Magento/InventoryAdminUi/Test/Mftf/Test/AdminCreateNewSourceAndCheckDisableSourceCodeTest.xml @@ -0,0 +1,60 @@ +<?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="AdminCreateNewSourceAndCheckDisableSourceCodeTest"> + <annotations> + <features value="Multi-Source Inventory"/> + <stories value="Add Source"/> + <title value="Disable source code field"/> + <description value="You should be able to create a New Source, via the Admin and check that the source code field is disabled after create."/> + <testCaseId value="1799"/> + <severity value="CRITICAL"/> + <group value="msi"/> + <group value="multi_mode"/> + </annotations> + + <before> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + </before> + + <after> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> + </after> + + <amOnPage url="{{AdminManageSourcePage.url}}" stepKey="amOnTheSourcesListPage"/> + + <comment userInput="Create new source" stepKey="createNewSource"/> + <click selector="{{AdminGridMainControls.add}}" stepKey="clickOnTheAddButton"/> + <fillField userInput="{{FullSource1.name}}" selector="{{AdminEditSourceGeneralSection.name}}" stepKey="fillNameField"/> + <fillField userInput="{{FullSource1.source_code}}" selector="{{AdminEditSourceGeneralSection.code}}" stepKey="fillCodeField"/> + <checkOption selector="{{AdminEditSourceGeneralSection.isEnabled}}" stepKey="checkIsEnabled"/> + <fillField userInput="{{FullSource1.description}}" selector="{{AdminEditSourceGeneralSection.description}}" stepKey="fillDescriptionField"/> + <fillField userInput="{{FullSource1.latitude}}" selector="{{AdminEditSourceGeneralSection.latitude}}" stepKey="fillLatitudeField"/> + <fillField userInput="{{FullSource1.longitude}}" selector="{{AdminEditSourceGeneralSection.longitude}}" stepKey="fillLongitudeField"/> + <conditionalClick selector="{{AdminEditSourceContactInfoSection.closed}}" dependentSelector="{{AdminEditSourceContactInfoSection.opened}}" visible="false" stepKey="clickOnContactInfo"/> + <waitForPageLoad time="30" stepKey="waitForContactInfoSectionClosed"/> + <fillField userInput="{{FullSource1.contact_name}}" selector="{{AdminEditSourceContactInfoSection.contactName}}" stepKey="fillContactNameField"/> + <fillField userInput="{{FullSource1.email}}" selector="{{AdminEditSourceContactInfoSection.email}}" stepKey="fillEmailField"/> + <fillField userInput="{{FullSource1.phone}}" selector="{{AdminEditSourceContactInfoSection.phone}}" stepKey="fillPhoneField"/> + <fillField userInput="{{FullSource1.fax}}" selector="{{AdminEditSourceContactInfoSection.fax}}" stepKey="fillFaxField"/> + <conditionalClick selector="{{AdminEditSourceAddressDataSection.closed}}" dependentSelector="{{AdminEditSourceAddressDataSection.opened}}" visible="false" stepKey="clickOnAddresses"/> + <waitForPageLoad time="30" stepKey="waitForAddressDataSectionClosed"/> + <selectOption userInput="{{FullSource1.country}}" selector="{{AdminEditSourceAddressDataSection.country}}" stepKey="selectCountry"/> + <selectOption userInput="{{FullSource1.stateProvince}}" selector="{{AdminEditSourceAddressDataSection.state}}" stepKey="selectState"/> + <fillField userInput="{{FullSource1.city}}" selector="{{AdminEditSourceAddressDataSection.city}}" stepKey="fillCityField"/> + <fillField userInput="{{FullSource1.street}}" selector="{{AdminEditSourceAddressDataSection.street}}" stepKey="fillStreetField"/> + <fillField userInput="{{FullSource1.postcode}}" selector="{{AdminEditSourceAddressDataSection.postcode}}" stepKey="fillPostcodeField"/> + <click selector="{{AdminGridMainControls.saveAndContinue}}" stepKey="clickOnSaveAndContinue"/> + <waitForPageLoad time="30" stepKey="waitForSourceSaved"/> + + <comment userInput="Check source code field is disabled" stepKey="checkDisabledSourceCode"/> + <assertElementContainsAttribute selector="{{AdminEditSourceGeneralSection.code}}" attribute="disabled" stepKey="seeSourceCodeFieldIsDisabled"/> + + </test> +</tests> diff --git a/app/code/Magento/InventoryCatalogSearch/Test/Mftf/Section/CatalogSearchResultSection.xml b/app/code/Magento/InventoryCatalogSearch/Test/Mftf/Section/CatalogSearchResultSection.xml new file mode 100644 index 000000000000..2721fa581b0c --- /dev/null +++ b/app/code/Magento/InventoryCatalogSearch/Test/Mftf/Section/CatalogSearchResultSection.xml @@ -0,0 +1,14 @@ +<?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="CatalogSearchResultSection"> + <element name="productListBlock" type="block" selector=".search.results"/> + </section> +</sections> diff --git a/app/code/Magento/InventorySales/Model/GetItemsToCancelFromOrderItem.php b/app/code/Magento/InventorySales/Model/GetItemsToCancelFromOrderItem.php new file mode 100644 index 000000000000..ae062dd228be --- /dev/null +++ b/app/code/Magento/InventorySales/Model/GetItemsToCancelFromOrderItem.php @@ -0,0 +1,129 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\InventorySales\Model; + +use Magento\Sales\Model\Order\Item as OrderItem; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; +use Magento\InventorySalesApi\Api\Data\ItemToSellInterfaceFactory; +use Magento\Framework\Serialize\Serializer\Json; + +class GetItemsToCancelFromOrderItem +{ + /** + * @var GetSkuFromOrderItemInterface + */ + private $getSkuFromOrderItem; + + /** + * @var ItemToSellInterfaceFactory + */ + private $itemsToSellFactory; + + /** + * @var Json + */ + private $jsonSerializer; + + /** + * @param GetSkuFromOrderItemInterface $getSkuFromOrderItem + * @param ItemToSellInterfaceFactory $itemsToSellFactory + * @param Json $jsonSerializer + */ + public function __construct( + GetSkuFromOrderItemInterface $getSkuFromOrderItem, + ItemToSellInterfaceFactory $itemsToSellFactory, + Json $jsonSerializer + ) { + $this->getSkuFromOrderItem = $getSkuFromOrderItem; + $this->itemsToSellFactory = $itemsToSellFactory; + $this->jsonSerializer = $jsonSerializer; + } + + /** + * @param OrderItem $orderItem + * @return array + */ + public function execute(OrderItem $orderItem): array + { + $itemsToSell = []; + if ($orderItem->getHasChildren()) { + if (!$orderItem->isDummy(true)) { + foreach ($this->processComplexItem($orderItem) as $item) { + $itemsToSell[] = $item; + } + } + } elseif (!$orderItem->isDummy(true)) { + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); + $qtyToCancel = $orderItem->getIsVirtual() ? $this->getQtyToCancelForVirtualItem($orderItem) + : $this->getQtyToCancelForPhysicalItem($orderItem); + $itemsToSell[] = $this->itemsToSellFactory->create([ + 'sku' => $itemSku, + 'qty' => $qtyToCancel + ]); + } + + return $itemsToSell; + } + + /** + * @param OrderItem $orderItem + * @return array + */ + private function processComplexItem(OrderItem $orderItem): array + { + $itemsToShip = []; + foreach ($orderItem->getChildrenItems() as $item) { + $productOptions = $item->getProductOptions(); + if (isset($productOptions['bundle_selection_attributes'])) { + $bundleSelectionAttributes = $this->jsonSerializer->unserialize( + $productOptions['bundle_selection_attributes'] + ); + if ($bundleSelectionAttributes) { + $qtyToCancel = $orderItem->getIsVirtual() ? $this->getQtyToCancelForVirtualItem($orderItem) + : $this->getQtyToCancelForPhysicalItem($orderItem); + $qty = $bundleSelectionAttributes['qty'] * $qtyToCancel; + $itemSku = $this->getSkuFromOrderItem->execute($item); + $itemsToShip[] = $this->itemsToSellFactory->create([ + 'sku' => $itemSku, + 'qty' => $qty + ]); + } + } else { + // configurable product + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); + $qtyToCancel = $orderItem->getIsVirtual() ? $this->getQtyToCancelForVirtualItem($orderItem) + : $this->getQtyToCancelForPhysicalItem($orderItem); + $itemsToShip[] = $this->itemsToSellFactory->create([ + 'sku' => $itemSku, + 'qty' => $qtyToCancel + ]); + } + } + + return $itemsToShip; + } + + /** + * @param OrderItem $item + * @return float + */ + private function getQtyToCancelForPhysicalItem(OrderItem $item): float + { + return $item->getQtyOrdered() - $item->getQtyShipped() - $item->getQtyCanceled(); + } + + /** + * @param OrderItem $item + * @return float + */ + private function getQtyToCancelForVirtualItem(OrderItem $item): float + { + return $item->getQtyOrdered() - $item->getQtyInvoiced() - $item->getQtyCanceled(); + } +} diff --git a/app/code/Magento/InventorySales/Model/GetSkuFromOrderItem.php b/app/code/Magento/InventorySales/Model/GetSkuFromOrderItem.php new file mode 100644 index 000000000000..94af036013f8 --- /dev/null +++ b/app/code/Magento/InventorySales/Model/GetSkuFromOrderItem.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\InventorySales\Model; + +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; +use Magento\Sales\Api\Data\OrderItemInterface; +use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use Magento\InventoryConfigurationApi\Model\IsSourceItemManagementAllowedForProductTypeInterface; + +class GetSkuFromOrderItem implements GetSkuFromOrderItemInterface +{ + /** + * @var GetSkusByProductIdsInterface + */ + private $getSkusByProductIds; + + /** + * @var IsSourceItemManagementAllowedForProductTypeInterface + */ + private $isSourceItemManagementAllowedForProductType; + + /** + * @param GetSkusByProductIdsInterface $getSkusByProductIds + * @param IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType + */ + public function __construct( + GetSkusByProductIdsInterface $getSkusByProductIds, + IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType + ) { + $this->getSkusByProductIds = $getSkusByProductIds; + $this->isSourceItemManagementAllowedForProductType = $isSourceItemManagementAllowedForProductType; + } + + /** + * @inheritdoc + */ + public function execute(OrderItemInterface $orderItem): string + { + try { + $itemSku = $orderItem->getSku(); + + if ($this->isSourceItemManagementAllowedForProductType->execute($orderItem->getProductType())) { + $itemSku = $this->getSkusByProductIds->execute( + [$orderItem->getProductId()] + )[$orderItem->getProductId()]; + } + } catch (NoSuchEntityException $e) { + $itemSku = $orderItem->getSku(); + } + + return $itemSku; + } +} diff --git a/app/code/Magento/InventorySales/Model/ReturnProcessor/GetInvoicedItemsPerSourceByPriority.php b/app/code/Magento/InventorySales/Model/ReturnProcessor/GetInvoicedItemsPerSourceByPriority.php index dfddc1721256..b00b8ed6e391 100644 --- a/app/code/Magento/InventorySales/Model/ReturnProcessor/GetInvoicedItemsPerSourceByPriority.php +++ b/app/code/Magento/InventorySales/Model/ReturnProcessor/GetInvoicedItemsPerSourceByPriority.php @@ -10,7 +10,7 @@ use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Model\Order\Invoice as InvoiceModel; use Magento\Sales\Model\Order\Item as OrderItemModel; -use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface; use Magento\InventoryApi\Api\GetSourceItemsBySkuInterface; use Magento\InventoryApi\Api\GetSourcesAssignedToStockOrderedByPriorityInterface; @@ -24,9 +24,9 @@ class GetInvoicedItemsPerSourceByPriority implements GetSourceDeductedOrderItemsInterface { /** - * @var GetSkusByProductIdsInterface + * @var GetSkuFromOrderItemInterface */ - private $getSkusByProductIds; + private $getSkuFromOrderItem; /** * @var StockByWebsiteIdResolverInterface @@ -59,7 +59,7 @@ class GetInvoicedItemsPerSourceByPriority implements GetSourceDeductedOrderItems private $sourceDeductedOrderItemsResultFactory; /** - * @param GetSkusByProductIdsInterface $getSkusByProductIds + * @param GetSkuFromOrderItemInterface $getSkuFromOrderItem * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver * @param GetSourcesAssignedToStockOrderedByPriorityInterface $getSourcesAssignedToStockOrderedByPriority * @param GetSourceItemsBySkuInterface $getSourceItemsBySku @@ -68,7 +68,7 @@ class GetInvoicedItemsPerSourceByPriority implements GetSourceDeductedOrderItems * @param SourceDeductedOrderItemsResultFactory $sourceDeductedOrderItemsResultFactory */ public function __construct( - GetSkusByProductIdsInterface $getSkusByProductIds, + GetSkuFromOrderItemInterface $getSkuFromOrderItem, StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, GetSourcesAssignedToStockOrderedByPriorityInterface $getSourcesAssignedToStockOrderedByPriority, GetSourceItemsBySkuInterface $getSourceItemsBySku, @@ -76,7 +76,7 @@ public function __construct( SourceDeductedOrderItemFactory $sourceDeductedOrderItemFactory, SourceDeductedOrderItemsResultFactory $sourceDeductedOrderItemsResultFactory ) { - $this->getSkusByProductIds = $getSkusByProductIds; + $this->getSkuFromOrderItem = $getSkuFromOrderItem; $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; $this->getSourcesAssignedToStockOrderedByPriority = $getSourcesAssignedToStockOrderedByPriority; $this->getSourceItemsBySku = $getSourceItemsBySku; @@ -89,7 +89,6 @@ public function __construct( * @param OrderInterface $order * @param array $returnToStockItems * @return SourceDeductedOrderItemsResult[] - * @throws \Magento\Framework\Exception\InputException */ public function execute(OrderInterface $order, array $returnToStockItems): array { @@ -97,10 +96,9 @@ public function execute(OrderInterface $order, array $returnToStockItems): array /** @var InvoiceModel $invoice */ foreach ($order->getInvoiceCollection() as $invoice) { foreach ($invoice->getItems() as $item) { - if ($this->isValidItem($item->getOrderItem(), $returnToStockItems)) { - $itemSku = $item->getSku() ?: $this->getSkusByProductIds->execute( - [$item->getProductId()] - )[$item->getProductId()]; + $orderItem = $item->getOrderItem(); + if ($this->isValidItem($orderItem, $returnToStockItems)) { + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); $invoicedItems[$itemSku] = ($invoicedItems[$itemSku] ?? 0) + $item->getQty(); } } diff --git a/app/code/Magento/InventorySales/Observer/CatalogInventory/CancelOrderItemObserver.php b/app/code/Magento/InventorySales/Observer/CatalogInventory/CancelOrderItemObserver.php index dc2e2a910e4f..ed8df44485fb 100644 --- a/app/code/Magento/InventorySales/Observer/CatalogInventory/CancelOrderItemObserver.php +++ b/app/code/Magento/InventorySales/Observer/CatalogInventory/CancelOrderItemObserver.php @@ -10,9 +10,7 @@ use Magento\Catalog\Model\Indexer\Product\Price\Processor; use Magento\Framework\Event\Observer as EventObserver; use Magento\Framework\Event\ObserverInterface; -use Magento\Framework\Exception\NoSuchEntityException; -use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; -use Magento\InventorySalesApi\Api\Data\ItemToSellInterfaceFactory; +use Magento\InventorySales\Model\GetItemsToCancelFromOrderItem; use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; use Magento\InventorySalesApi\Api\Data\SalesChannelInterfaceFactory; use Magento\InventorySalesApi\Api\Data\SalesEventInterface; @@ -33,11 +31,6 @@ class CancelOrderItemObserver implements ObserverInterface */ private $salesEventFactory; - /** - * @var GetSkusByProductIdsInterface - */ - private $getSkusByProductIds; - /** * @var PlaceReservationsForSalesEventInterface */ @@ -49,103 +42,71 @@ class CancelOrderItemObserver implements ObserverInterface private $salesChannelFactory; /** - * @var ItemToSellInterfaceFactory + * @var WebsiteRepositoryInterface */ - private $itemsToSellFactory; + private $websiteRepository; /** - * @var WebsiteRepositoryInterface + * @var GetItemsToCancelFromOrderItem */ - private $websiteRepository; + private $getItemsToCancelFromOrderItem; /** * @param Processor $priceIndexer * @param SalesEventInterfaceFactory $salesEventFactory - * @param GetSkusByProductIdsInterface $getSkusByProductIds * @param PlaceReservationsForSalesEventInterface $placeReservationsForSalesEvent * @param SalesChannelInterfaceFactory $salesChannelFactory - * @param ItemToSellInterfaceFactory $itemsToSellFactory * @param WebsiteRepositoryInterface $websiteRepository + * @param GetItemsToCancelFromOrderItem $getItemsToCancelFromOrderItem */ public function __construct( Processor $priceIndexer, SalesEventInterfaceFactory $salesEventFactory, - GetSkusByProductIdsInterface $getSkusByProductIds, PlaceReservationsForSalesEventInterface $placeReservationsForSalesEvent, SalesChannelInterfaceFactory $salesChannelFactory, - ItemToSellInterfaceFactory $itemsToSellFactory, - WebsiteRepositoryInterface $websiteRepository + WebsiteRepositoryInterface $websiteRepository, + GetItemsToCancelFromOrderItem $getItemsToCancelFromOrderItem ) { $this->priceIndexer = $priceIndexer; $this->salesEventFactory = $salesEventFactory; - $this->getSkusByProductIds = $getSkusByProductIds; $this->placeReservationsForSalesEvent = $placeReservationsForSalesEvent; $this->salesChannelFactory = $salesChannelFactory; - $this->itemsToSellFactory = $itemsToSellFactory; $this->websiteRepository = $websiteRepository; + $this->getItemsToCancelFromOrderItem = $getItemsToCancelFromOrderItem; } /** * @param EventObserver $observer * @return void */ - public function execute(EventObserver $observer) + public function execute(EventObserver $observer): void { /** @var OrderItem $item */ - $item = $observer->getEvent()->getItem(); - $qty = $item->getQtyToCancel(); - if ($this->canCancelOrderItem($item) && $qty) { - try { - $productSku = $item->getSku() ?: $this->getSkusByProductIds->execute( - [$item->getProductId()] - )[$item->getProductId()]; - } catch (NoSuchEntityException $e) { - /** - * As it was decided the Inventory should not use data constraints depending on Catalog - * (these two systems are not highly coupled, i.e. Magento does not sync data between them, so that - * it's possible that SKU exists in Catalog, but does not exist in Inventory and vice versa) - * it is necessary for Magento to have an ability to process placed orders even with - * deleted or non-existing products - */ - return; - } - - $itemToSell = $this->itemsToSellFactory->create([ - 'sku' => $productSku, - 'qty' => (float)$qty - ]); - - $websiteId = $item->getStore()->getWebsiteId(); - $websiteCode = $this->websiteRepository->getById($websiteId)->getCode(); - $salesChannel = $this->salesChannelFactory->create([ - 'data' => [ - 'type' => SalesChannelInterface::TYPE_WEBSITE, - 'code' => $websiteCode - ] - ]); - - /** @var SalesEventInterface $salesEvent */ - $salesEvent = $this->salesEventFactory->create([ - 'type' => SalesEventInterface::EVENT_ORDER_CANCELED, - 'objectType' => SalesEventInterface::OBJECT_TYPE_ORDER, - 'objectId' => (string)$item->getOrderId() - ]); - - $this->placeReservationsForSalesEvent->execute([$itemToSell], $salesChannel, $salesEvent); - } + $orderItem = $observer->getEvent()->getItem(); - $this->priceIndexer->reindexRow($item->getProductId()); - } + $itemsToSell = $this->getItemsToCancelFromOrderItem->execute($orderItem); - /** - * @param OrderItem $orderItem - * @return bool - */ - private function canCancelOrderItem(OrderItem $orderItem): bool - { - if ($orderItem->getId() && $orderItem->getProductId() && !$orderItem->isDummy()) { - return true; + if (empty($itemsToSell)) { + return; } - return false; + + $websiteId = $orderItem->getStore()->getWebsiteId(); + $websiteCode = $this->websiteRepository->getById($websiteId)->getCode(); + $salesChannel = $this->salesChannelFactory->create([ + 'data' => [ + 'type' => SalesChannelInterface::TYPE_WEBSITE, + 'code' => $websiteCode + ] + ]); + + $salesEvent = $this->salesEventFactory->create([ + 'type' => SalesEventInterface::EVENT_ORDER_CANCELED, + 'objectType' => SalesEventInterface::OBJECT_TYPE_ORDER, + 'objectId' => (string)$orderItem->getOrderId() + ]); + + $this->placeReservationsForSalesEvent->execute($itemsToSell, $salesChannel, $salesEvent); + + $this->priceIndexer->reindexRow($orderItem->getProductId()); } } diff --git a/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessBackItemQtyPlugin.php b/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessBackItemQtyPlugin.php index 32150397aba2..707446e0a474 100644 --- a/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessBackItemQtyPlugin.php +++ b/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessBackItemQtyPlugin.php @@ -13,9 +13,12 @@ use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; use Magento\InventoryConfigurationApi\Model\IsSourceItemManagementAllowedForProductTypeInterface; -use Magento\InventoryReservationsApi\Model\AppendReservationsInterface; -use Magento\InventoryReservationsApi\Model\ReservationBuilderInterface; -use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; +use Magento\InventorySalesApi\Api\Data\ItemToSellInterfaceFactory; +use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; +use Magento\InventorySalesApi\Api\Data\SalesChannelInterfaceFactory; +use Magento\InventorySalesApi\Api\Data\SalesEventInterfaceFactory; +use Magento\InventorySalesApi\Api\PlaceReservationsForSalesEventInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; /** * Class provides around Plugin on \Magento\CatalogInventory\Model\StockManagement::backItemQty @@ -28,19 +31,29 @@ class ProcessBackItemQtyPlugin private $getSkusByProductIds; /** - * @var StockByWebsiteIdResolverInterface + * @var SalesEventInterfaceFactory */ - private $stockByWebsiteIdResolver; + private $salesEventFactory; /** - * @var ReservationBuilderInterface + * @var SalesChannelInterfaceFactory */ - private $reservationBuilder; + private $salesChannelFactory; /** - * @var AppendReservationsInterface + * @var ItemToSellInterfaceFactory */ - private $appendReservations; + private $itemsToSellFactory; + + /** + * @var WebsiteRepositoryInterface + */ + private $websiteRepository; + + /** + * @var PlaceReservationsForSalesEventInterface + */ + private $placeReservationsForSalesEvent; /** * @var IsSourceItemManagementAllowedForProductTypeInterface @@ -54,24 +67,30 @@ class ProcessBackItemQtyPlugin /** * @param GetSkusByProductIdsInterface $getSkusByProductIds - * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver - * @param ReservationBuilderInterface $reservationBuilder - * @param AppendReservationsInterface $appendReservations + * @param SalesEventInterfaceFactory $salesEventFactory + * @param SalesChannelInterfaceFactory $salesChannelFactory + * @param ItemToSellInterfaceFactory $itemsToSellFactory + * @param WebsiteRepositoryInterface $websiteRepository + * @param PlaceReservationsForSalesEventInterface $placeReservationsForSalesEvent * @param IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType * @param GetProductTypesBySkusInterface $getProductTypesBySkus */ public function __construct( GetSkusByProductIdsInterface $getSkusByProductIds, - StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, - ReservationBuilderInterface $reservationBuilder, - AppendReservationsInterface $appendReservations, + SalesEventInterfaceFactory $salesEventFactory, + SalesChannelInterfaceFactory $salesChannelFactory, + ItemToSellInterfaceFactory $itemsToSellFactory, + WebsiteRepositoryInterface $websiteRepository, + PlaceReservationsForSalesEventInterface $placeReservationsForSalesEvent, IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType, GetProductTypesBySkusInterface $getProductTypesBySkus ) { $this->getSkusByProductIds = $getSkusByProductIds; - $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; - $this->reservationBuilder = $reservationBuilder; - $this->appendReservations = $appendReservations; + $this->salesEventFactory = $salesEventFactory; + $this->salesChannelFactory = $salesChannelFactory; + $this->itemsToSellFactory = $itemsToSellFactory; + $this->websiteRepository = $websiteRepository; + $this->placeReservationsForSalesEvent = $placeReservationsForSalesEvent; $this->isSourceItemManagementAllowedForProductType = $isSourceItemManagementAllowedForProductType; $this->getProductTypesBySkus = $getProductTypesBySkus; } @@ -113,13 +132,26 @@ public function aroundBackItemQty( $productType = $this->getProductTypesBySkus->execute([$productSku])[$productSku]; if (true === $this->isSourceItemManagementAllowedForProductType->execute($productType)) { - $stockId = (int)$this->stockByWebsiteIdResolver->execute((int)$scopeId)->getStockId(); - $reservation = $this->reservationBuilder - ->setSku($productSku) - ->setQuantity((float)$qty) - ->setStockId($stockId) - ->build(); - $this->appendReservations->execute([$reservation]); + $websiteCode = $this->websiteRepository->getById((int)$scopeId)->getCode(); + $salesChannel = $this->salesChannelFactory->create([ + 'data' => [ + 'type' => SalesChannelInterface::TYPE_WEBSITE, + 'code' => $websiteCode + ] + ]); + + $salesEvent = $this->salesEventFactory->create([ + 'type' => 'back_item_qty', + 'objectType' => 'legacy_stock_management_api', + 'objectId' => 'none' + ]); + + $itemToSell = $this->itemsToSellFactory->create([ + 'sku' => $productSku, + 'qty' => (float)$qty + ]); + + $this->placeReservationsForSalesEvent->execute([$itemToSell], $salesChannel, $salesEvent); } return true; diff --git a/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessRevertProductsSalePlugin.php b/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessRevertProductsSalePlugin.php index a4e00fe3df92..c4626843e433 100644 --- a/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessRevertProductsSalePlugin.php +++ b/app/code/Magento/InventorySales/Plugin/CatalogInventory/StockManagement/ProcessRevertProductsSalePlugin.php @@ -7,15 +7,17 @@ namespace Magento\InventorySales\Plugin\CatalogInventory\StockManagement; -use Magento\CatalogInventory\Api\Data\StockItemInterface; use Magento\CatalogInventory\Model\StockManagement; use Magento\Framework\Exception\LocalizedException; use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; use Magento\InventoryConfigurationApi\Model\IsSourceItemManagementAllowedForProductTypeInterface; -use Magento\InventoryReservationsApi\Model\AppendReservationsInterface; -use Magento\InventoryReservationsApi\Model\ReservationBuilderInterface; -use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; +use Magento\InventorySalesApi\Api\Data\ItemToSellInterfaceFactory; +use Magento\InventorySalesApi\Api\Data\SalesChannelInterface; +use Magento\InventorySalesApi\Api\Data\SalesChannelInterfaceFactory; +use Magento\InventorySalesApi\Api\Data\SalesEventInterfaceFactory; +use Magento\InventorySalesApi\Api\PlaceReservationsForSalesEventInterface; +use Magento\Store\Api\WebsiteRepositoryInterface; /** * Class provides around Plugin on \Magento\CatalogInventory\Model\StockManagement::revertProductsSale @@ -28,19 +30,29 @@ class ProcessRevertProductsSalePlugin private $getSkusByProductIds; /** - * @var StockByWebsiteIdResolverInterface + * @var SalesEventInterfaceFactory */ - private $stockByWebsiteIdResolver; + private $salesEventFactory; /** - * @var ReservationBuilderInterface + * @var SalesChannelInterfaceFactory */ - private $reservationBuilder; + private $salesChannelFactory; /** - * @var AppendReservationsInterface + * @var ItemToSellInterfaceFactory */ - private $appendReservations; + private $itemsToSellFactory; + + /** + * @var WebsiteRepositoryInterface + */ + private $websiteRepository; + + /** + * @var PlaceReservationsForSalesEventInterface + */ + private $placeReservationsForSalesEvent; /** * @var IsSourceItemManagementAllowedForProductTypeInterface @@ -54,26 +66,32 @@ class ProcessRevertProductsSalePlugin /** * @param GetSkusByProductIdsInterface $getSkusByProductIds - * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver - * @param ReservationBuilderInterface $reservationBuilder - * @param AppendReservationsInterface $appendReservations + * @param SalesEventInterfaceFactory $salesEventFactory + * @param SalesChannelInterfaceFactory $salesChannelFactory + * @param ItemToSellInterfaceFactory $itemsToSellFactory + * @param WebsiteRepositoryInterface $websiteRepository + * @param PlaceReservationsForSalesEventInterface $placeReservationsForSalesEvent * @param IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType * @param GetProductTypesBySkusInterface $getProductTypesBySkus */ public function __construct( GetSkusByProductIdsInterface $getSkusByProductIds, - StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, - ReservationBuilderInterface $reservationBuilder, - AppendReservationsInterface $appendReservations, + SalesEventInterfaceFactory $salesEventFactory, + SalesChannelInterfaceFactory $salesChannelFactory, + ItemToSellInterfaceFactory $itemsToSellFactory, + WebsiteRepositoryInterface $websiteRepository, + PlaceReservationsForSalesEventInterface $placeReservationsForSalesEvent, IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType, GetProductTypesBySkusInterface $getProductTypesBySkus ) { $this->getSkusByProductIds = $getSkusByProductIds; - $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; - $this->reservationBuilder = $reservationBuilder; - $this->appendReservations = $appendReservations; $this->isSourceItemManagementAllowedForProductType = $isSourceItemManagementAllowedForProductType; $this->getProductTypesBySkus = $getProductTypesBySkus; + $this->salesEventFactory = $salesEventFactory; + $this->salesChannelFactory = $salesChannelFactory; + $this->itemsToSellFactory = $itemsToSellFactory; + $this->websiteRepository = $websiteRepository; + $this->placeReservationsForSalesEvent = $placeReservationsForSalesEvent; } /** @@ -81,38 +99,53 @@ public function __construct( * @param callable $proceed * @param float[] $items * @param int|null $websiteId - * @return StockItemInterface[] + * @return bool * @throws LocalizedException * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function aroundRevertProductsSale(StockManagement $subject, callable $proceed, $items, $websiteId = null) - { + public function aroundRevertProductsSale( + StockManagement $subject, + callable $proceed, + $items, + $websiteId = null + ): bool { if (empty($items)) { - return []; + return true; } + if (null === $websiteId) { throw new LocalizedException(__('$websiteId parameter is required')); } - $stockId = (int)$this->stockByWebsiteIdResolver->execute((int)$websiteId)->getStockId(); + $websiteCode = $this->websiteRepository->getById((int)$websiteId)->getCode(); + $salesChannel = $this->salesChannelFactory->create([ + 'data' => [ + 'type' => SalesChannelInterface::TYPE_WEBSITE, + 'code' => $websiteCode + ] + ]); + + $salesEvent = $this->salesEventFactory->create([ + 'type' => 'revert_products_sale', + 'objectType' => 'legacy_stock_management_api', + 'objectId' => 'none' + ]); + $productSkus = $this->getSkusByProductIds->execute(array_keys($items)); $productTypes = $this->getProductTypesBySkus->execute(array_values($productSkus)); - $reservations = []; + $itemsToSell = []; foreach ($productSkus as $productId => $sku) { - if (false === $this->isSourceItemManagementAllowedForProductType->execute($productTypes[$sku])) { - continue; + if (true === $this->isSourceItemManagementAllowedForProductType->execute($productTypes[$sku])) { + $itemsToSell[] = $this->itemsToSellFactory->create([ + 'sku' => $sku, + 'qty' => (float)$items[$productId] + ]); } - $reservations[] = $this->reservationBuilder - ->setSku($sku) - ->setQuantity((float)$items[$productId]) - ->setStockId($stockId) - ->build(); - } - if (!empty($reservations)) { - $this->appendReservations->execute($reservations); } - return []; + $this->placeReservationsForSalesEvent->execute($itemsToSell, $salesChannel, $salesEvent); + + return true; } } diff --git a/app/code/Magento/InventorySales/Plugin/SalesInventory/ProcessReturnQtyOnCreditMemoPlugin.php b/app/code/Magento/InventorySales/Plugin/SalesInventory/ProcessReturnQtyOnCreditMemoPlugin.php index 94b2d5bffd26..8fd41ca6f513 100644 --- a/app/code/Magento/InventorySales/Plugin/SalesInventory/ProcessReturnQtyOnCreditMemoPlugin.php +++ b/app/code/Magento/InventorySales/Plugin/SalesInventory/ProcessReturnQtyOnCreditMemoPlugin.php @@ -12,7 +12,7 @@ use Magento\Sales\Api\Data\CreditmemoInterface; use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\OrderItemInterface; -use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; use Magento\SalesInventory\Model\Order\ReturnProcessor; use Magento\InventoryConfigurationApi\Model\IsSourceItemManagementAllowedForProductTypeInterface; use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; @@ -20,9 +20,9 @@ class ProcessReturnQtyOnCreditMemoPlugin { /** - * @var GetSkusByProductIdsInterface + * @var GetSkuFromOrderItemInterface */ - private $getSkusByProductIds; + private $getSkuFromOrderItem; /** * @var ItemsToRefundInterfaceFactory @@ -45,20 +45,20 @@ class ProcessReturnQtyOnCreditMemoPlugin private $getProductTypesBySkus; /** - * @param GetSkusByProductIdsInterface $getSkusByProductIds + * @param GetSkuFromOrderItemInterface $getSkuFromOrderItem * @param ItemsToRefundInterfaceFactory $itemsToRefundFactory * @param ProcessRefundItemsInterface $processRefundItems * @param IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType * @param GetProductTypesBySkusInterface $getProductTypesBySkus */ public function __construct( - GetSkusByProductIdsInterface $getSkusByProductIds, + GetSkuFromOrderItemInterface $getSkuFromOrderItem, ItemsToRefundInterfaceFactory $itemsToRefundFactory, ProcessRefundItemsInterface $processRefundItems, IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType, GetProductTypesBySkusInterface $getProductTypesBySkus ) { - $this->getSkusByProductIds = $getSkusByProductIds; + $this->getSkuFromOrderItem = $getSkuFromOrderItem; $this->itemsToRefundFactory = $itemsToRefundFactory; $this->processRefundItems = $processRefundItems; $this->isSourceItemManagementAllowedForProductType = $isSourceItemManagementAllowedForProductType; @@ -73,8 +73,6 @@ public function __construct( * @param array $returnToStockItems * @param bool $isAutoReturn * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * - * @throws \Magento\Framework\Exception\NoSuchEntityException */ public function aroundExecute( ReturnProcessor $subject, @@ -88,9 +86,7 @@ public function aroundExecute( foreach ($creditmemo->getItems() as $item) { /** @var OrderItemInterface $orderItem */ $orderItem = $item->getOrderItem(); - $itemSku = $item->getSku() ?: $this->getSkusByProductIds->execute( - [$item->getProductId()] - )[$item->getProductId()]; + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); if ($this->isValidItem($itemSku, $orderItem->getProductType())) { $qty = (float)$item->getQty(); diff --git a/app/code/Magento/InventorySales/etc/di.xml b/app/code/Magento/InventorySales/etc/di.xml index 6d1c0bfc0eda..caafcc4226d3 100644 --- a/app/code/Magento/InventorySales/etc/di.xml +++ b/app/code/Magento/InventorySales/etc/di.xml @@ -169,4 +169,5 @@ <plugin name="load_stock_item_is_in_stock" type="Magento\InventoryCatalog\Plugin\InventoryConfigurationApi\GetStockItemConfiguration\LoadIsInStockPlugin"/> </type> + <preference for="Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface" type="Magento\InventorySales\Model\GetSkuFromOrderItem"/> </config> diff --git a/app/code/Magento/InventorySalesApi/Model/GetSkuFromOrderItemInterface.php b/app/code/Magento/InventorySalesApi/Model/GetSkuFromOrderItemInterface.php new file mode 100644 index 000000000000..347da2692be9 --- /dev/null +++ b/app/code/Magento/InventorySalesApi/Model/GetSkuFromOrderItemInterface.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +declare(strict_types=1); + +namespace Magento\InventorySalesApi\Model; + +use Magento\Sales\Api\Data\OrderItemInterface; + +interface GetSkuFromOrderItemInterface +{ + /** + * @param OrderItemInterface $orderItem + * @return string + */ + public function execute(OrderItemInterface $orderItem): string; +} diff --git a/app/code/Magento/InventoryShipping/Model/GetItemsToDeductFromShipment.php b/app/code/Magento/InventoryShipping/Model/GetItemsToDeductFromShipment.php index 590fda85b33a..5314fbf20c10 100644 --- a/app/code/Magento/InventoryShipping/Model/GetItemsToDeductFromShipment.php +++ b/app/code/Magento/InventoryShipping/Model/GetItemsToDeductFromShipment.php @@ -10,7 +10,7 @@ use Magento\Sales\Model\Order\Shipment\Item; use Magento\Sales\Model\Order\Item as OrderItem; use Magento\Framework\Serialize\Serializer\Json; -use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; use Magento\InventorySourceDeductionApi\Model\ItemToDeductInterface; use Magento\InventorySourceDeductionApi\Model\ItemToDeductInterfaceFactory; use Magento\Sales\Model\Order\Shipment; @@ -19,9 +19,9 @@ class GetItemsToDeductFromShipment { /** - * @var GetSkusByProductIdsInterface + * @var GetSkuFromOrderItemInterface */ - private $getSkusByProductIds; + private $getSkuFromOrderItem; /** * @var Json @@ -34,18 +34,18 @@ class GetItemsToDeductFromShipment private $itemToDeduct; /** - * @param GetSkusByProductIdsInterface $getSkusByProductIds + * @param GetSkuFromOrderItemInterface $getSkuFromOrderItem * @param Json $jsonSerializer * @param ItemToDeductInterfaceFactory $itemToDeduct */ public function __construct( - GetSkusByProductIdsInterface $getSkusByProductIds, + GetSkuFromOrderItemInterface $getSkuFromOrderItem, Json $jsonSerializer, ItemToDeductInterfaceFactory $itemToDeduct ) { - $this->getSkusByProductIds = $getSkusByProductIds; $this->jsonSerializer = $jsonSerializer; $this->itemToDeduct = $itemToDeduct; + $this->getSkuFromOrderItem = $getSkuFromOrderItem; } /** @@ -72,9 +72,7 @@ public function execute(Shipment $shipment): array } } } else { - $itemSku = $shipmentItem->getSku() ?: $this->getSkusByProductIds->execute( - [$shipmentItem->getProductId()] - )[$shipmentItem->getProductId()]; + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); $qty = $this->castQty($orderItem, $shipmentItem->getQty()); $itemsToShip[] = $this->itemToDeduct->create([ 'sku' => $itemSku, @@ -114,7 +112,6 @@ private function groupItemsBySku(array $shipmentItems): array /** * @param Item $shipmentItem * @return array - * @throws NoSuchEntityException */ private function processComplexItem(Item $shipmentItem): array { @@ -132,9 +129,7 @@ private function processComplexItem(Item $shipmentItem): array if ($bundleSelectionAttributes) { $qty = $bundleSelectionAttributes['qty'] * $shipmentItem->getQty(); $qty = $this->castQty($item, $qty); - $itemSku = $item->getSku() ?: $this->getSkusByProductIds->execute( - [$item->getProductId()] - )[$item->getProductId()]; + $itemSku = $this->getSkuFromOrderItem->execute($item); $itemsToShip[] = $this->itemToDeduct->create([ 'sku' => $itemSku, 'qty' => $qty @@ -143,9 +138,7 @@ private function processComplexItem(Item $shipmentItem): array } } else { // configurable product - $itemSku = $shipmentItem->getSku() ?: $this->getSkusByProductIds->execute( - [$shipmentItem->getProductId()] - )[$shipmentItem->getProductId()]; + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); $qty = $this->castQty($orderItem, $shipmentItem->getQty()); $itemsToShip[] = $this->itemToDeduct->create([ 'sku' => $itemSku, diff --git a/app/code/Magento/InventoryShipping/Model/GetSourceSelectionResultFromInvoice.php b/app/code/Magento/InventoryShipping/Model/GetSourceSelectionResultFromInvoice.php index 50556301a257..e815a9915752 100644 --- a/app/code/Magento/InventoryShipping/Model/GetSourceSelectionResultFromInvoice.php +++ b/app/code/Magento/InventoryShipping/Model/GetSourceSelectionResultFromInvoice.php @@ -7,16 +7,13 @@ namespace Magento\InventoryShipping\Model; -use Magento\Framework\Exception\InputException; -use Magento\Framework\Exception\NoSuchEntityException; -use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; use Magento\InventorySourceSelectionApi\Api\Data\InventoryRequestInterface; use Magento\InventorySourceSelectionApi\Api\Data\InventoryRequestInterfaceFactory; use Magento\InventorySourceSelectionApi\Api\Data\ItemRequestInterfaceFactory; use Magento\Sales\Api\Data\InvoiceInterface; use Magento\Sales\Api\Data\InvoiceItemInterface; -use Magento\Sales\Model\Order\Invoice\Item as InvoiceItemModel; use Magento\Sales\Api\Data\OrderItemInterface; use Magento\InventorySourceSelectionApi\Api\SourceSelectionServiceInterface; use Magento\InventorySourceSelectionApi\Api\GetDefaultSourceSelectionAlgorithmCodeInterface; @@ -30,9 +27,9 @@ class GetSourceSelectionResultFromInvoice { /** - * @var GetSkusByProductIdsInterface + * @var GetSkuFromOrderItemInterface */ - private $getSkusByProductIds; + private $getSkuFromOrderItem; /** * @var ItemRequestInterfaceFactory @@ -60,7 +57,7 @@ class GetSourceSelectionResultFromInvoice private $sourceSelectionService; /** - * @param GetSkusByProductIdsInterface $getSkusByProductIds + * @param GetSkuFromOrderItemInterface $getSkuFromOrderItem * @param ItemRequestInterfaceFactory $itemRequestFactory * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver * @param InventoryRequestInterfaceFactory $inventoryRequestFactory @@ -68,25 +65,24 @@ class GetSourceSelectionResultFromInvoice * @param SourceSelectionServiceInterface $sourceSelectionService */ public function __construct( - GetSkusByProductIdsInterface $getSkusByProductIds, + GetSkuFromOrderItemInterface $getSkuFromOrderItem, ItemRequestInterfaceFactory $itemRequestFactory, StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, InventoryRequestInterfaceFactory $inventoryRequestFactory, GetDefaultSourceSelectionAlgorithmCodeInterface $getDefaultSourceSelectionAlgorithmCode, SourceSelectionServiceInterface $sourceSelectionService ) { - $this->getSkusByProductIds = $getSkusByProductIds; $this->itemRequestFactory = $itemRequestFactory; $this->inventoryRequestFactory = $inventoryRequestFactory; $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; $this->getDefaultSourceSelectionAlgorithmCode = $getDefaultSourceSelectionAlgorithmCode; $this->sourceSelectionService = $sourceSelectionService; + $this->getSkuFromOrderItem = $getSkuFromOrderItem; } /** * @param InvoiceInterface $invoice * @return SourceSelectionResultInterface - * @throws InputException */ public function execute(InvoiceInterface $invoice): SourceSelectionResultInterface { @@ -107,7 +103,6 @@ public function execute(InvoiceInterface $invoice): SourceSelectionResultInterfa /** * @param InvoiceItemInterface[]|Traversable $invoiceItems * @return array - * @throws NoSuchEntityException */ private function getSelectionRequestItems(Traversable $invoiceItems): array { @@ -119,9 +114,7 @@ private function getSelectionRequestItems(Traversable $invoiceItems): array continue; } - $itemSku = $invoiceItem->getSku() ?: $this->getSkusByProductIds->execute( - [$invoiceItem->getProductId()] - )[$invoiceItem->getProductId()]; + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); $qty = $this->castQty($invoiceItem->getOrderItem(), $invoiceItem->getQty()); $selectionRequestItems[] = $this->itemRequestFactory->create([ diff --git a/app/code/Magento/InventoryShipping/Model/InventoryRequestFromOrderFactory.php b/app/code/Magento/InventoryShipping/Model/InventoryRequestFromOrderFactory.php index 09f7bdd97fdb..acdf65400ba4 100644 --- a/app/code/Magento/InventoryShipping/Model/InventoryRequestFromOrderFactory.php +++ b/app/code/Magento/InventoryShipping/Model/InventoryRequestFromOrderFactory.php @@ -14,7 +14,7 @@ use Magento\InventorySourceSelectionApi\Api\Data\ItemRequestInterfaceFactory; use Magento\InventorySourceSelectionApi\Api\Data\InventoryRequestInterfaceFactory; use Magento\InventorySalesApi\Model\StockByWebsiteIdResolverInterface; -use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; class InventoryRequestFromOrderFactory { @@ -34,27 +34,26 @@ class InventoryRequestFromOrderFactory private $stockByWebsiteIdResolver; /** - * @var GetSkusByProductIdsInterface + * @var GetSkuFromOrderItemInterface */ - private $getSkusByProductIds; + private $getSkuFromOrderItem; /** - * InventoryRequestFactory constructor. * @param ItemRequestInterfaceFactory $itemRequestFactory * @param InventoryRequestInterfaceFactory $inventoryRequestFactory * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver - * @param GetSkusByProductIdsInterface $getSkusByProductIds + * @param GetSkuFromOrderItemInterface $getSkuFromOrderItem */ public function __construct( ItemRequestInterfaceFactory $itemRequestFactory, InventoryRequestInterfaceFactory $inventoryRequestFactory, StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, - GetSkusByProductIdsInterface $getSkusByProductIds + GetSkuFromOrderItemInterface $getSkuFromOrderItem ) { $this->itemRequestFactory = $itemRequestFactory; $this->inventoryRequestFactory = $inventoryRequestFactory; $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; - $this->getSkusByProductIds = $getSkusByProductIds; + $this->getSkuFromOrderItem = $getSkuFromOrderItem; } /** @@ -69,9 +68,7 @@ public function create(OrderInterface $order) : InventoryRequestInterface /** @var OrderItemInterface|OrderItem $orderItem */ foreach ($order->getItems() as $orderItem) { - $itemSku = $orderItem->getSku() ?: $this->getSkusByProductIds->execute( - [$orderItem->getProductId()] - )[$orderItem->getProductId()]; + $itemSku = $this->getSkuFromOrderItem->execute($orderItem); $qtyToDeliver = $orderItem->getQtyToShip(); //check if order item is not delivered yet diff --git a/app/code/Magento/InventoryShippingAdminUi/Ui/DataProvider/SourceSelectionDataProvider.php b/app/code/Magento/InventoryShippingAdminUi/Ui/DataProvider/SourceSelectionDataProvider.php index 112fd8cf4261..fc50aa8ceb61 100644 --- a/app/code/Magento/InventoryShippingAdminUi/Ui/DataProvider/SourceSelectionDataProvider.php +++ b/app/code/Magento/InventoryShippingAdminUi/Ui/DataProvider/SourceSelectionDataProvider.php @@ -17,6 +17,7 @@ use Magento\InventoryConfigurationApi\Api\GetStockItemConfigurationInterface; use Magento\Framework\App\RequestInterface; use Magento\InventoryShippingAdminUi\Ui\DataProvider\GetSourcesByStockIdSkuAndQty; +use Magento\InventorySalesApi\Model\GetSkuFromOrderItemInterface; class SourceSelectionDataProvider extends AbstractDataProvider { @@ -45,6 +46,11 @@ class SourceSelectionDataProvider extends AbstractDataProvider */ private $getSourcesByStockIdSkuAndQty; + /** + * @var GetSkuFromOrderItemInterface + */ + private $getSkuFromOrderItem; + /** * @var array */ @@ -59,6 +65,7 @@ class SourceSelectionDataProvider extends AbstractDataProvider * @param StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver * @param GetStockItemConfigurationInterface $getStockItemConfiguration * @param GetSourcesByStockIdSkuAndQty $getSourcesByStockIdSkuAndQty + * @param GetSkuFromOrderItemInterface $getSkuFromOrderItem * @param array $meta * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -72,6 +79,7 @@ public function __construct( StockByWebsiteIdResolverInterface $stockByWebsiteIdResolver, GetStockItemConfigurationInterface $getStockItemConfiguration, GetSourcesByStockIdSkuAndQty $getSourcesByStockIdSkuAndQty, + GetSkuFromOrderItemInterface $getSkuFromOrderItem, array $meta = [], array $data = [] ) { @@ -81,6 +89,7 @@ public function __construct( $this->stockByWebsiteIdResolver = $stockByWebsiteIdResolver; $this->getStockItemConfiguration = $getStockItemConfiguration; $this->getSourcesByStockIdSkuAndQty = $getSourcesByStockIdSkuAndQty; + $this->getSkuFromOrderItem = $getSkuFromOrderItem; } /** @@ -122,7 +131,7 @@ public function getData() $qty = $orderItem->getSimpleQtyToShip(); $qty = $this->castQty($orderItem, $qty); - $sku = $orderItem->getSku(); + $sku = $this->getSkuFromOrderItem->execute($orderItem); $data[$orderId]['items'][] = [ 'orderItemId' => $orderItemId, 'sku' => $sku, diff --git a/app/code/Magento/InventorySourceDeductionApi/Model/GetSourceItemBySourceCodeAndSku.php b/app/code/Magento/InventorySourceDeductionApi/Model/GetSourceItemBySourceCodeAndSku.php index b94e488fc8b4..871bbbcb3501 100644 --- a/app/code/Magento/InventorySourceDeductionApi/Model/GetSourceItemBySourceCodeAndSku.php +++ b/app/code/Magento/InventorySourceDeductionApi/Model/GetSourceItemBySourceCodeAndSku.php @@ -10,6 +10,7 @@ use Magento\Framework\Api\SearchCriteriaBuilder; use Magento\InventoryApi\Api\Data\SourceItemInterface; use Magento\InventoryApi\Api\SourceItemRepositoryInterface; +use Magento\Framework\Exception\NoSuchEntityException; /** * Retrieve source item from specific source by given SKU. @@ -43,9 +44,10 @@ public function __construct( * * @param string $sourceCode * @param string $sku - * @return SourceItemInterface|null + * @return SourceItemInterface + * @throws NoSuchEntityException */ - public function execute(string $sourceCode, string $sku) + public function execute(string $sourceCode, string $sku): SourceItemInterface { $searchCriteria = $this->searchCriteriaBuilder ->addFilter(SourceItemInterface::SOURCE_CODE, $sourceCode) @@ -53,6 +55,12 @@ public function execute(string $sourceCode, string $sku) ->create(); $sourceItemsResult = $this->sourceItemRepository->getList($searchCriteria); - return $sourceItemsResult->getTotalCount() > 0 ? current($sourceItemsResult->getItems()) : null; + if ($sourceItemsResult->getTotalCount() === 0) { + throw new NoSuchEntityException( + __('Source item not found by source code: %1 and sku: %2.', $sourceCode, $sku) + ); + } + + return current($sourceItemsResult->getItems()); } }