From 19267d44a0c0a21d2df56ad521784c3a884d0a46 Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Tue, 12 Aug 2025 14:04:52 -0500 Subject: [PATCH 01/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../web/js/model/pickup-locations-service.js | 49 ++++++++++++++++++- ...ExtractQuoteAddressShippingAddressData.php | 5 ++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js index 57a3df18556..6c843d75868 100644 --- a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js +++ b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js @@ -12,6 +12,9 @@ define([ 'Magento_Checkout/js/checkout-data', 'Magento_Checkout/js/model/address-converter', 'Magento_Checkout/js/action/select-shipping-address', + 'Magento_Checkout/js/action/select-billing-address', + 'Magento_Checkout/js/model/checkout-data-resolver', + 'Magento_Checkout/js/model/quote', 'underscore', 'mage/translate', 'mage/url', @@ -25,6 +28,9 @@ define([ checkoutData, addressConverter, selectShippingAddressAction, + selectBillingAddressAction, + checkoutDataResolver, + quote, _, $t, url, @@ -104,7 +110,7 @@ define([ }, /** - * Select location for sipping. + * Select location for shipping. * * @param {Object} location * @param {Boolean} [persist=true] @@ -137,6 +143,11 @@ define([ addressConverter.quoteAddressToFormAddressData(address) ); } + var billingAddress = quote.billingAddress(); + if (!billingAddress || this.isBillingAddressIncomplete(billingAddress)) { + selectBillingAddressAction(address); + checkoutDataResolver.resolveBillingAddress(); + } }, /** @@ -191,6 +202,42 @@ define([ return regions && regions[regionId] ? regions[regionId].name : ''; }, + /** + * Check if billing address is incomplete (missing required fields) + * + * @param {Object} billingAddress + * @returns {Boolean} + */ + isBillingAddressIncomplete: function (billingAddress) { + if (!billingAddress) { + return true; + } + var requiredFields = [ + 'firstname', + 'lastname', + 'street', + 'city', + 'postcode', + 'telephone', + 'regionId', + 'countryId' + ]; + for (var i = 0; i < requiredFields.length; i++) { + var field = requiredFields[i]; + var value = billingAddress[field]; + if (field === 'street') { + if (!value || !Array.isArray(value) || value.length === 0 || !value[0]) { + return true; + } + } else { + if (!value || value === '' || value === null || value === undefined) { + return true; + } + } + } + return false; + }, + /** * Process response errors. * diff --git a/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php b/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php index c4216d08faa..0474a7cf6bb 100644 --- a/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php +++ b/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php @@ -9,6 +9,7 @@ use Magento\Framework\DataObject\Copy; use Magento\Quote\Api\Data\AddressInterface; +use Magento\InventoryInStorePickupShippingApi\Model\Carrier\InStorePickup; /** * Extract quote address details according to fieldset config. @@ -49,6 +50,10 @@ public function execute(AddressInterface $address): array if (isset($data[AddressInterface::KEY_STREET]) && is_array($data[AddressInterface::KEY_STREET])) { $data[AddressInterface::KEY_STREET] = implode("\n", $data[AddressInterface::KEY_STREET]); } + $data[AddressInterface::SAME_AS_BILLING] = false; + $data[AddressInterface::SAVE_IN_ADDRESS_BOOK] = false; + $data[AddressInterface::CUSTOMER_ADDRESS_ID] = null; + $data['shipping_method'] = InStorePickup::DELIVERY_METHOD; return $data; } From 21dd76af60ef12488968f28f8013447917cb241d Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Tue, 12 Aug 2025 14:42:33 -0500 Subject: [PATCH 02/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- ...ExtractQuoteAddressShippingAddressData.php | 4 - ...actQuoteAddressShippingAddressDataTest.php | 95 +++++++++++++++++++ 2 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 InventoryInStorePickupQuote/Test/Unit/Model/ExtractQuoteAddressShippingAddressDataTest.php diff --git a/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php b/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php index 0474a7cf6bb..543f332e8dc 100644 --- a/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php +++ b/InventoryInStorePickupQuote/Model/ExtractQuoteAddressShippingAddressData.php @@ -43,10 +43,6 @@ public function execute(AddressInterface $address): array 'shipping_address_data', $address ); - - // TODO: temporary solution to avoid issue with config merge. - $data['customer_address_id'] = $address->getCustomerAddressId(); - if (isset($data[AddressInterface::KEY_STREET]) && is_array($data[AddressInterface::KEY_STREET])) { $data[AddressInterface::KEY_STREET] = implode("\n", $data[AddressInterface::KEY_STREET]); } diff --git a/InventoryInStorePickupQuote/Test/Unit/Model/ExtractQuoteAddressShippingAddressDataTest.php b/InventoryInStorePickupQuote/Test/Unit/Model/ExtractQuoteAddressShippingAddressDataTest.php new file mode 100644 index 00000000000..c9dc58d820e --- /dev/null +++ b/InventoryInStorePickupQuote/Test/Unit/Model/ExtractQuoteAddressShippingAddressDataTest.php @@ -0,0 +1,95 @@ +objectCopyServiceMock = $this->createMock(Copy::class); + $this->addressMock = $this->createMock(AddressInterface::class); + $this->extractor = new ExtractQuoteAddressShippingAddressData( + $this->objectCopyServiceMock + ); + } + + /** + * Test execute method to verify specific data values + */ + public function testExecuteWithValidAddressData(): void + { + $addressData = [ + AddressInterface::KEY_STREET => ['123 Main St', 'Apt 4B'], + 'some_field' => 'some_value' + ]; + $this->objectCopyServiceMock + ->method('getDataFromFieldset') + ->with('sales_convert_quote_address', 'shipping_address_data', $this->addressMock) + ->willReturn($addressData); + $result = $this->extractor->execute($this->addressMock); + $expectedData = [ + AddressInterface::KEY_STREET => "123 Main St\nApt 4B", + 'some_field' => 'some_value', + AddressInterface::SAME_AS_BILLING => false, + AddressInterface::SAVE_IN_ADDRESS_BOOK => false, + AddressInterface::CUSTOMER_ADDRESS_ID => null, + 'shipping_method' => InStorePickup::DELIVERY_METHOD + ]; + $this->assertEquals($expectedData, $result); + } + + /** + * Test execute method with non-array street field + */ + public function testExecuteWithNonArrayStreetField(): void + { + $addressData = [ + AddressInterface::KEY_STREET => '123 Main St', + 'some_field' => 'some_value' + ]; + $this->objectCopyServiceMock + ->method('getDataFromFieldset') + ->with('sales_convert_quote_address', 'shipping_address_data', $this->addressMock) + ->willReturn($addressData); + $result = $this->extractor->execute($this->addressMock); + $expectedData = [ + AddressInterface::KEY_STREET => '123 Main St', + 'some_field' => 'some_value', + AddressInterface::SAME_AS_BILLING => false, + AddressInterface::SAVE_IN_ADDRESS_BOOK => false, + AddressInterface::CUSTOMER_ADDRESS_ID => null, + 'shipping_method' => InStorePickup::DELIVERY_METHOD + ]; + $this->assertEquals($expectedData, $result); + } +} From 7b7b9abcabc498b50365d57de7106ac406ee195a Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 18 Aug 2025 15:55:37 -0500 Subject: [PATCH 03/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../web/js/model/pickup-locations-service.js | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js index 6c843d75868..e4b590d037a 100644 --- a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js +++ b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js @@ -117,6 +117,8 @@ define([ * @returns void */ selectForShipping: function (location, persist) { + var billingAddress = quote.billingAddress(); + var address = $.extend( {}, addressConverter.formAddressDataToQuoteAddress({ @@ -143,7 +145,6 @@ define([ addressConverter.quoteAddressToFormAddressData(address) ); } - var billingAddress = quote.billingAddress(); if (!billingAddress || this.isBillingAddressIncomplete(billingAddress)) { selectBillingAddressAction(address); checkoutDataResolver.resolveBillingAddress(); @@ -209,10 +210,10 @@ define([ * @returns {Boolean} */ isBillingAddressIncomplete: function (billingAddress) { - if (!billingAddress) { - return true; - } - var requiredFields = [ + var field, + value, + counter, + requiredFields = [ 'firstname', 'lastname', 'street', @@ -222,17 +223,18 @@ define([ 'regionId', 'countryId' ]; - for (var i = 0; i < requiredFields.length; i++) { - var field = requiredFields[i]; - var value = billingAddress[field]; - if (field === 'street') { - if (!value || !Array.isArray(value) || value.length === 0 || !value[0]) { - return true; - } - } else { - if (!value || value === '' || value === null || value === undefined) { - return true; - } + + if (!billingAddress) { + return true; + } + for (counter = 0; counter < requiredFields.length; counter++) { + field = requiredFields[counter]; + value = billingAddress[field]; + if (field === 'street' && (!value || !Array.isArray(value) || value.length === 0 || !value[0])) { + return true; + } + if (field !== 'street' && (!value || value === '' || value === null || value === undefined)) { + return true; } } return false; @@ -257,7 +259,7 @@ define([ try { error = JSON.parse(response.responseText); - } catch (exception) { + } catch { error = $t( 'Something went wrong with your request. Please try again later.' ); From f5ab9667892fc601c592e314d3949b7f808ff412 Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 18 Aug 2025 16:55:57 -0500 Subject: [PATCH 04/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../view/frontend/web/js/model/pickup-locations-service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js index e4b590d037a..2daf38c4960 100644 --- a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js +++ b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js @@ -259,7 +259,7 @@ define([ try { error = JSON.parse(response.responseText); - } catch { + } catch (exception) { // eslint-disable-line no-unused-vars error = $t( 'Something went wrong with your request. Please try again later.' ); From b101539e7214b4d4cf1841de3f7e91e79e9c580a Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 18 Aug 2025 20:49:51 -0500 Subject: [PATCH 05/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../view/frontend/web/js/model/pickup-locations-service.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js index 2daf38c4960..883387a0b23 100644 --- a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js +++ b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js @@ -117,9 +117,8 @@ define([ * @returns void */ selectForShipping: function (location, persist) { - var billingAddress = quote.billingAddress(); - - var address = $.extend( + var billingAddress = quote.billingAddress(), + address = $.extend( {}, addressConverter.formAddressDataToQuoteAddress({ firstname: location.name, @@ -222,7 +221,7 @@ define([ 'telephone', 'regionId', 'countryId' - ]; + ]; if (!billingAddress) { return true; From bd7de3313d3829d364d4af3a7f99a6383fd584ef Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Tue, 19 Aug 2025 08:58:49 -0500 Subject: [PATCH 06/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../web/js/model/pickup-locations-service.js | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js index 883387a0b23..c6cc3355801 100644 --- a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js +++ b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js @@ -119,21 +119,21 @@ define([ selectForShipping: function (location, persist) { var billingAddress = quote.billingAddress(), address = $.extend( - {}, - addressConverter.formAddressDataToQuoteAddress({ - firstname: location.name, - lastname: 'Store', - street: location.street, - city: location.city, - postcode: location.postcode, - 'country_id': location['country_id'], - telephone: location.telephone, - 'region_id': location['region_id'], - 'save_in_address_book': 0, - 'extension_attributes': { - 'pickup_location_code': location['pickup_location_code'] - } - })); + {}, + addressConverter.formAddressDataToQuoteAddress({ + firstname: location.name, + lastname: 'Store', + street: location.street, + city: location.city, + postcode: location.postcode, + 'country_id': location['country_id'], + telephone: location.telephone, + 'region_id': location['region_id'], + 'save_in_address_book': 0, + 'extension_attributes': { + 'pickup_location_code': location['pickup_location_code'] + } + })); address = pickupAddressConverter.formatAddressToPickupAddress(address); this.selectedLocation(location); From c490bf76c275cfa3da1dc7cf503678e2431639b8 Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Tue, 19 Aug 2025 11:20:02 -0500 Subject: [PATCH 07/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- ...efrontAssertPaymentInformationActionGroup.xml | 2 +- .../web/js/model/pickup-locations-service.js | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml index 4011af4e799..5aa66ed2050 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml @@ -12,7 +12,7 @@ Verify, payment information is correct on Review And Payment page. - + diff --git a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js index c6cc3355801..15d77450c57 100644 --- a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js +++ b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js @@ -213,14 +213,14 @@ define([ value, counter, requiredFields = [ - 'firstname', - 'lastname', - 'street', - 'city', - 'postcode', - 'telephone', - 'regionId', - 'countryId' + 'firstname', + 'lastname', + 'street', + 'city', + 'postcode', + 'telephone', + 'regionId', + 'countryId' ]; if (!billingAddress) { From 1892bb38c6dd930a7c0731aa4f2d00c95a95ec75 Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Tue, 19 Aug 2025 13:41:38 -0500 Subject: [PATCH 08/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../StorefrontAssertPaymentInformationActionGroup.xml | 2 +- ...essFilledAutomaticallyWithSimpleProductCustomStockTest.xml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml index 5aa66ed2050..4011af4e799 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontAssertPaymentInformationActionGroup.xml @@ -12,7 +12,7 @@ Verify, payment information is correct on Review And Payment page. - + diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml index 8df4e554d66..cf4d6ea5b7b 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml @@ -103,6 +103,8 @@ - + + + From 42d9e24e63fdcf35f28ce6ac876098c897c2844a Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Tue, 19 Aug 2025 14:14:56 -0500 Subject: [PATCH 09/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- ...dressFilledAutomaticallyWithSimpleProductCustomStockTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml index cf4d6ea5b7b..6ded15d08f3 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml @@ -103,7 +103,7 @@ - + From 6706677340833f107eb84ca282c3333929854b14 Mon Sep 17 00:00:00 2001 From: glo5363 Date: Thu, 28 Aug 2025 17:12:09 +0530 Subject: [PATCH 10/46] ACQE-8580: [MFTF TESTS] AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest - Fixes for bulk operation message checks --- ...kAssignSourcesToBulkSimpleProductsActionGroup.xml | 12 +++++++++++- .../Section/AdminBulkSourceAssignmentSection.xml | 1 + ...nProductsGridToUnAssignAllAssignedSourcesTest.xml | 1 - 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml index f8acfda12f3..3ba0c51fce8 100755 --- a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml +++ b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml @@ -61,7 +61,17 @@ - + + + + + Bulk operation was successful: + $grabSuccessMessage + + + assignments. + $grabSuccessMessage + diff --git a/InventoryAdminUi/Test/Mftf/Section/AdminBulkSourceAssignmentSection.xml b/InventoryAdminUi/Test/Mftf/Section/AdminBulkSourceAssignmentSection.xml index 88144517e8c..49bfe8f963e 100755 --- a/InventoryAdminUi/Test/Mftf/Section/AdminBulkSourceAssignmentSection.xml +++ b/InventoryAdminUi/Test/Mftf/Section/AdminBulkSourceAssignmentSection.xml @@ -15,5 +15,6 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest.xml index b5e639ade27..1a50a23c4ff 100755 --- a/InventoryAdminUi/Test/Mftf/Test/AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest.xml @@ -17,7 +17,6 @@ - From ae1f68e4d93e19b72a7b0470d80f9d68b26beb90 Mon Sep 17 00:00:00 2001 From: glo5363 Date: Mon, 1 Sep 2025 20:34:34 +0530 Subject: [PATCH 11/46] ACQE-8580: [MFTF TESTS] AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest - Fixes for bulk operation message assertion --- ...inBulkAssignSourcesToBulkSimpleProductsActionGroup.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml index 3ba0c51fce8..8702fd95b02 100755 --- a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml +++ b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml @@ -65,12 +65,12 @@ - Bulk operation was successful: - $grabSuccessMessage + Bulk operation was successful: + $grabSuccessMessage - assignments. - $grabSuccessMessage + assignments. + $grabSuccessMessage From e2fdd971d32ec4e503e947e037c93185546ee27d Mon Sep 17 00:00:00 2001 From: Karishma Thakare Date: Wed, 3 Sep 2025 00:46:23 +0530 Subject: [PATCH 12/46] ACQE-7267: [MFTF TESTS] StorefrontPickUpSourceInfoSimpleProductCustomStockTest - Removed pr exclude - Updated InsertImageIcon selector --- .../Test/Mftf/Section/AdminEditSourcePickupLocationSection.xml | 2 +- .../StorefrontPickUpSourceInfoSimpleProductCustomStockTest.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Section/AdminEditSourcePickupLocationSection.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Section/AdminEditSourcePickupLocationSection.xml index d4bad407eaf..555b9708e3d 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Section/AdminEditSourcePickupLocationSection.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Section/AdminEditSourcePickupLocationSection.xml @@ -9,6 +9,6 @@
- +
diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontPickUpSourceInfoSimpleProductCustomStockTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontPickUpSourceInfoSimpleProductCustomStockTest.xml index b207e8d2b89..d5339548e29 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontPickUpSourceInfoSimpleProductCustomStockTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontPickUpSourceInfoSimpleProductCustomStockTest.xml @@ -16,7 +16,6 @@ - From 2bb88fe6923dfa99d904048352669e993848da32 Mon Sep 17 00:00:00 2001 From: glo5363 Date: Wed, 3 Sep 2025 14:13:55 +0530 Subject: [PATCH 13/46] ACQE-8580: [MFTF TESTS] AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest - Fixes for bulk operation message assertion --- .../AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml index 8702fd95b02..335cab76b52 100755 --- a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml +++ b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml @@ -69,7 +69,7 @@ $grabSuccessMessage - assignments. + 16 assignments. $grabSuccessMessage From d898509cc7083d5b72281ba84219983a3868b7c4 Mon Sep 17 00:00:00 2001 From: glo5363 Date: Fri, 5 Sep 2025 16:24:08 +0530 Subject: [PATCH 14/46] ACQE-8580: [MFTF TESTS] AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest - Code Review fixes --- .../AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml index 335cab76b52..4da4a308860 100755 --- a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml +++ b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkAssignSourcesToBulkSimpleProductsActionGroup.xml @@ -63,7 +63,6 @@ - Bulk operation was successful: $grabSuccessMessage From 4ffb9c28718bb35f6acd40d92780d7f6db3f0d1f Mon Sep 17 00:00:00 2001 From: chandrakalahanchinal Date: Mon, 8 Sep 2025 15:53:00 +0530 Subject: [PATCH 15/46] ACQE-8501: [MFTF TESTS] StorefrontSummaryShippingSectionWithSimpleProductCustomStockTest - Added skip tag for test. - ACQE-8501: Added skip tag for test --- .../Mftf/Test/StorefrontGuestBillingAddressPreselectedTest.xml | 3 +++ ...tSummaryShippingSectionWithSimpleProductCustomStockTest.xml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontGuestBillingAddressPreselectedTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontGuestBillingAddressPreselectedTest.xml index 954d4d45f9f..63782548267 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontGuestBillingAddressPreselectedTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontGuestBillingAddressPreselectedTest.xml @@ -19,6 +19,9 @@ + + Skipped because of AC bug + diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontSummaryShippingSectionWithSimpleProductCustomStockTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontSummaryShippingSectionWithSimpleProductCustomStockTest.xml index e014f5efcf2..6473299e0cf 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontSummaryShippingSectionWithSimpleProductCustomStockTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontSummaryShippingSectionWithSimpleProductCustomStockTest.xml @@ -17,6 +17,9 @@ + + Skipped because of AC bug + From 39467583ce8befffdb88193dedb8656fd7e6d9f9 Mon Sep 17 00:00:00 2001 From: glo5363 Date: Mon, 8 Sep 2025 15:57:11 +0530 Subject: [PATCH 16/46] ACQE-8580: [MFTF TESTS] AdminUserApplyToSeveralSimpleProductsMassActionUnAssignProductSourcesOnProductsGridToUnAssignAllAssignedSourcesTest - Fixes for AdminBulkUnAssignSourcesToBulkSimpleProductsActionGroup as well to assert unassignment message --- ...UnAssignSourcesToBulkSimpleProductsActionGroup.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkUnAssignSourcesToBulkSimpleProductsActionGroup.xml b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkUnAssignSourcesToBulkSimpleProductsActionGroup.xml index 78d7b3da213..9c78fa09259 100755 --- a/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkUnAssignSourcesToBulkSimpleProductsActionGroup.xml +++ b/InventoryAdminUi/Test/Mftf/ActionGroup/AdminBulkUnAssignSourcesToBulkSimpleProductsActionGroup.xml @@ -62,7 +62,16 @@ - + + + + Bulk operation was successful: + $grabUnassignmentSuccessMessage + + + 16 unassignments. + $$grabUnassignmentSuccessMessage +
From a5c5b9271ea521c33d176111438ad7fb237de99c Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 8 Sep 2025 12:14:36 -0500 Subject: [PATCH 17/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../ShippingInformationManagementPlugin.php | 89 +++++++++ ...hippingInformationManagementPluginTest.php | 179 ++++++++++++++++++ InventoryInStorePickupQuote/etc/di.xml | 3 + 3 files changed, 271 insertions(+) create mode 100644 InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php create mode 100644 InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php diff --git a/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php b/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php new file mode 100644 index 00000000000..a202ca43092 --- /dev/null +++ b/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php @@ -0,0 +1,89 @@ +getShippingAddress(); + $billingAddress = $addressInformation->getBillingAddress(); + + if ($this->isPickupStoreShipping($address) && $this->isBillingAddressIncomplete($billingAddress)) { + $addressInformation->setBillingAddress($address); + } + + return [$cartId, $addressInformation]; + } + + /** + * Check if shipping method is in-store pickup + * + * @param AddressInterface|null $shippingAddress + * @return bool + */ + private function isPickupStoreShipping(?AddressInterface $shippingAddress): bool + { + if (!$shippingAddress) { + return false; + } + $extensionAttributes = $shippingAddress->getExtensionAttributes(); + if ($extensionAttributes && $extensionAttributes->getPickupLocationCode()) { + return true; + } + return false; + } + + /** + * Check if billing address is incomplete (missing required fields) + * + * @param AddressInterface|null $billingAddress + * @return bool + */ + private function isBillingAddressIncomplete(?AddressInterface $billingAddress): bool + { + if (!$billingAddress) { + return true; + } + $requiredFields = [ + 'firstname', + 'lastname', + 'street', + 'city', + 'postcode', + 'telephone', + 'regionId', + 'countryId' + ]; + foreach ($requiredFields as $field) { + $getter = 'get' . ucfirst($field); + if (method_exists($billingAddress, $getter) && !$billingAddress->$getter()) { + return true; + } + } + return false; + } +} diff --git a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php new file mode 100644 index 00000000000..b37e27dcaaf --- /dev/null +++ b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php @@ -0,0 +1,179 @@ +subject = $this->getMockBuilder(ShippingInformationManagement::class) + ->disableOriginalConstructor() + ->getMock(); + $this->addressInformation = $this->getMockBuilder(ShippingInformationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->shippingAddress = $this->getMockBuilder(AddressInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->billingAddress = $this->getMockBuilder(AddressInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->extensionAttributes = $this->getMockBuilder(AddressExtensionInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->plugin = new ShippingInformationManagementPlugin(); + } + + /** + * Test beforeSaveAddressInformation when billing address is incomplete + * + * @return void + */ + public function testBeforeSaveAddressInformationPickupStoreIncompleteBilling(): void + { + $cartId = 123; + $pickupLocationCode = 'store_001'; + $this->shippingAddress->expects($this->once()) + ->method('getExtensionAttributes') + ->willReturn($this->extensionAttributes); + $this->extensionAttributes->expects($this->once()) + ->method('getPickupLocationCode') + ->willReturn($pickupLocationCode); + $this->billingAddress->expects($this->once()) + ->method('getFirstname') + ->willReturn(null); + $this->addressInformation->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddress); + $this->addressInformation->expects($this->once()) + ->method('getBillingAddress') + ->willReturn($this->billingAddress); + $this->addressInformation->expects($this->once()) + ->method('setBillingAddress') + ->with($this->shippingAddress); + $result = $this->plugin->beforeSaveAddressInformation( + $this->subject, + $cartId, + $this->addressInformation + ); + $this->assertEquals([$cartId, $this->addressInformation], $result); + } + + /** + * Test beforeSaveAddressInformation when billing address is complete + * + * @return void + */ + public function testBeforeSaveAddressInformationPickupStoreCompleteBilling(): void + { + $cartId = 123; + $pickupLocationCode = 'store_001'; + $this->shippingAddress->expects($this->once()) + ->method('getExtensionAttributes') + ->willReturn($this->extensionAttributes); + $this->extensionAttributes->expects($this->once()) + ->method('getPickupLocationCode') + ->willReturn($pickupLocationCode); + $this->billingAddress->expects($this->once())->method('getFirstname')->willReturn('Test'); + $this->billingAddress->expects($this->once())->method('getLastname')->willReturn('Test'); + $this->billingAddress->expects($this->once())->method('getStreet')->willReturn(['123 Test Street']); + $this->billingAddress->expects($this->once())->method('getCity')->willReturn('Austin'); + $this->billingAddress->expects($this->once())->method('getPostcode')->willReturn('78758'); + $this->billingAddress->expects($this->once())->method('getTelephone')->willReturn('512-1234567'); + $this->billingAddress->expects($this->once())->method('getRegionId')->willReturn(12); + $this->billingAddress->expects($this->once())->method('getCountryId')->willReturn('US'); + $this->addressInformation->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddress); + $this->addressInformation->expects($this->once()) + ->method('getBillingAddress') + ->willReturn($this->billingAddress); + $this->addressInformation->expects($this->never())->method('setBillingAddress'); + $result = $this->plugin->beforeSaveAddressInformation( + $this->subject, + $cartId, + $this->addressInformation + ); + $this->assertEquals([$cartId, $this->addressInformation], $result); + } + + /** + * Test beforeSaveAddressInformation when pickup store shipping is false + * + * @return void + */ + public function testBeforeSaveAddressInformationNotPickupStore(): void + { + $cartId = 123; + $this->shippingAddress->expects($this->once()) + ->method('getExtensionAttributes') + ->willReturn($this->extensionAttributes); + $this->extensionAttributes->expects($this->once()) + ->method('getPickupLocationCode') + ->willReturn(null); + $this->addressInformation->expects($this->once()) + ->method('getShippingAddress') + ->willReturn($this->shippingAddress); + $this->addressInformation->expects($this->once()) + ->method('getBillingAddress') + ->willReturn($this->billingAddress); + $this->addressInformation->expects($this->never())->method('setBillingAddress'); + $result = $this->plugin->beforeSaveAddressInformation( + $this->subject, + $cartId, + $this->addressInformation + ); + $this->assertEquals([$cartId, $this->addressInformation], $result); + } +} diff --git a/InventoryInStorePickupQuote/etc/di.xml b/InventoryInStorePickupQuote/etc/di.xml index 7677508c62e..50336d6ab90 100644 --- a/InventoryInStorePickupQuote/etc/di.xml +++ b/InventoryInStorePickupQuote/etc/di.xml @@ -37,4 +37,7 @@ + + + From 67e598e9f35de2b71fb27521e62f3cb9e1cc4d6a Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 8 Sep 2025 13:22:36 -0500 Subject: [PATCH 18/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../Plugin/Checkout/ShippingInformationManagementPlugin.php | 1 + InventoryInStorePickupQuote/composer.json | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php b/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php index a202ca43092..84880e20597 100644 --- a/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php +++ b/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php @@ -23,6 +23,7 @@ class ShippingInformationManagementPlugin * @param int $cartId * @param ShippingInformationInterface $addressInformation * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function beforeSaveAddressInformation( ShippingInformationManagement $subject, diff --git a/InventoryInStorePickupQuote/composer.json b/InventoryInStorePickupQuote/composer.json index b5b7501b69b..c0fc039133e 100644 --- a/InventoryInStorePickupQuote/composer.json +++ b/InventoryInStorePickupQuote/composer.json @@ -10,7 +10,8 @@ "magento/module-inventory-in-store-pickup-shipping-api": "*", "magento/module-store": "*", "magento/module-customer": "*", - "magento/module-inventory-sales-api": "*" + "magento/module-inventory-sales-api": "*", + "magento/module-checkout": "*" }, "type": "magento2-module", "license": [ From 1390f5c803b269bc4880452cd03ecc1b076a35dc Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 8 Sep 2025 14:50:17 -0500 Subject: [PATCH 19/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../ShippingInformationManagementPluginTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php index b37e27dcaaf..b0a68239583 100644 --- a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php +++ b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php @@ -64,12 +64,26 @@ protected function setUp(): void ->disableOriginalConstructor() ->getMockForAbstractClass(); $this->shippingAddress = $this->getMockBuilder(AddressInterface::class) + ->onlyMethods(['getExtensionAttributes']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $this->billingAddress = $this->getMockBuilder(AddressInterface::class) + ->onlyMethods( + [ + 'getFirstname', + 'getLastname', + 'getStreet', + 'getCity', + 'getPostcode', + 'getTelephone', + 'getRegionId', + 'getCountryId' + ] + ) ->disableOriginalConstructor() ->getMockForAbstractClass(); $this->extensionAttributes = $this->getMockBuilder(AddressExtensionInterface::class) + ->onlyMethods(['getPickupLocationCode']) ->disableOriginalConstructor() ->getMockForAbstractClass(); $this->plugin = new ShippingInformationManagementPlugin(); From 160562b780f10b1107149c3153382f8a596a06af Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 8 Sep 2025 16:55:34 -0500 Subject: [PATCH 20/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../Checkout/ShippingInformationManagementPluginTest.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php index b0a68239583..716cd80f964 100644 --- a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php +++ b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php @@ -10,7 +10,6 @@ use Magento\Checkout\Api\Data\ShippingInformationInterface; use Magento\Checkout\Model\ShippingInformationManagement; use Magento\InventoryInStorePickupQuote\Plugin\Checkout\ShippingInformationManagementPlugin; -use Magento\Quote\Api\Data\AddressExtensionInterface; use Magento\Quote\Api\Data\AddressInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -48,7 +47,7 @@ class ShippingInformationManagementPluginTest extends TestCase private $billingAddress; /** - * @var AddressExtensionInterface|MockObject + * @var AddressInterface|MockObject */ private $extensionAttributes; @@ -82,10 +81,7 @@ protected function setUp(): void ) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->extensionAttributes = $this->getMockBuilder(AddressExtensionInterface::class) - ->onlyMethods(['getPickupLocationCode']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); + $this->extensionAttributes = $this->createMock(AddressInterface::class); $this->plugin = new ShippingInformationManagementPlugin(); } From 983bfc4aa89759e16f37354ea49b3e329c13407d Mon Sep 17 00:00:00 2001 From: Sokly Meach Date: Mon, 8 Sep 2025 17:32:11 -0500 Subject: [PATCH 21/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../Checkout/ShippingInformationManagementPluginTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php index 716cd80f964..e318bf1aebf 100644 --- a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php +++ b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php @@ -11,6 +11,7 @@ use Magento\Checkout\Model\ShippingInformationManagement; use Magento\InventoryInStorePickupQuote\Plugin\Checkout\ShippingInformationManagementPlugin; use Magento\Quote\Api\Data\AddressInterface; +use Magento\Quote\Api\Data\AddressExtensionInterface; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -81,7 +82,10 @@ protected function setUp(): void ) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->extensionAttributes = $this->createMock(AddressInterface::class); + $this->extensionAttributes = $this->getMockBuilder(AddressExtensionInterface::class) + ->addMethods(['getPickupLocationCode']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); $this->plugin = new ShippingInformationManagementPlugin(); } From 22f82aa4f807d61bcf23302d1284968c4593c160 Mon Sep 17 00:00:00 2001 From: glo5363 Date: Thu, 14 Aug 2025 18:51:41 +0530 Subject: [PATCH 22/46] ACQE-8275: [ATLH] Customers CE. Initial list of tests which do not delete customers - Fixes applied to remove customer data generated by API pattern --- ...tOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml | 1 + ...nSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml | 1 + .../Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml | 1 + ...tToCartAfterCancelOrderConfigurableProductCustomStockTest.xml | 1 + ...CacheValidationConfigurableProductSoldOutCustomStocksTest.xml | 1 + ...nfigurableProductWithDropDownAttributeAndCustomSourceTest.xml | 1 + ...MemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml | 1 + ...tForWholeOrderWithConfigurableProductFromCustomSourceTest.xml | 1 + ...ForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml | 1 + ...WithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml | 1 + ...edWithConfigurableProductWithTextAttributeViaTheAdminTest.xml | 1 + ...ValidationConfigurableProductSoldOutInSingleStockModeTest.xml | 1 + ...tCreateOrderAllQuantityConfigurableProductCustomStockTest.xml | 1 + ...eOrderAllOptionQuantityConfigurableProductCustomStockTest.xml | 1 + ...nfigurableProductWithDropDownAttributeAndCustomSourceTest.xml | 1 + ...figurableProductWithDropDownAttributeAndDefaultSourceTest.xml | 1 + ...ntLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml | 1 + ...thZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml | 1 + ...figurableProductNotVisibleAfterDisablingChildProductsTest.xml | 1 + 19 files changed, 19 insertions(+) diff --git a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml index 75cb453423c..595f2e49f87 100644 --- a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml +++ b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml @@ -71,6 +71,7 @@ + diff --git a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml index d3609a2fe33..9d3e1083ac6 100644 --- a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml +++ b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml @@ -46,6 +46,7 @@ + diff --git a/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml b/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml index 226e056d183..8425fb6d72c 100644 --- a/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml +++ b/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml @@ -35,6 +35,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml index 323e2326a99..554a5ce003b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml @@ -70,6 +70,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml index 51aa0939879..8132f854dd8 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml @@ -46,6 +46,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml index ad9be518338..8207fb196e9 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml @@ -70,6 +70,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml index 02e3ca62258..2f174f8fe12 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml @@ -75,6 +75,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml index ef8ae624489..af682627842 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml @@ -78,6 +78,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml index 959a4663b1f..68b626c9412 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml @@ -61,6 +61,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml index c526fb61670..0560a8863ee 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml @@ -57,6 +57,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml index 25e79d06b77..a98c8ac7974 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml @@ -57,6 +57,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml index f0e2389ec6c..2989d775aea 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml @@ -57,6 +57,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml index ef53581358a..cb974fe53da 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml @@ -75,6 +75,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml index 585455c8c4d..1b34e45a3ea 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml @@ -103,6 +103,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml index ea8627fe076..911ca0055d7 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml @@ -76,6 +76,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml index 035c1d5e573..624489d23c5 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml @@ -65,6 +65,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml index 9e893db8b2d..cff084d6c2e 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml @@ -62,6 +62,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml b/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml index 737f1f577bf..918bfd09fd0 100644 --- a/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml @@ -214,6 +214,7 @@ + diff --git a/InventoryCatalogSearchConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductNotVisibleAfterDisablingChildProductsTest.xml b/InventoryCatalogSearchConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductNotVisibleAfterDisablingChildProductsTest.xml index 52ce978fc03..4342f8c5a99 100644 --- a/InventoryCatalogSearchConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductNotVisibleAfterDisablingChildProductsTest.xml +++ b/InventoryCatalogSearchConfigurableProduct/Test/Mftf/Test/StorefrontConfigurableProductNotVisibleAfterDisablingChildProductsTest.xml @@ -114,6 +114,7 @@ + From 5f49e8431e056be1079d5a265a6e0000c501f90b Mon Sep 17 00:00:00 2001 From: glo5363 Date: Thu, 14 Aug 2025 19:32:23 +0530 Subject: [PATCH 23/46] ACQE-8275: [ATLH] Customers CE. Initial list of tests which do not delete customers - Fixes applied to remove customer data by grid deletion pattern --- ...kNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml | 4 ++++ ...thSimpleProductAdditionalStockAdditionalWebsiteTest.xml | 7 +++++++ ...erWithSimpleProductOnTestStockFromCustomWebsiteTest.xml | 4 ++++ ...ustomStockCustomWebsiteBySkuFromCustomerAccountTest.xml | 4 ++++ ...eOrderWithSimpleProductCustomStockCustomWebsiteTest.xml | 6 +++++- ...eviewAndPaymentPageWithSimpleProductCustomStockTest.xml | 6 +++++- 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml index aba6691bf7f..8fc1f5b0751 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml @@ -23,6 +23,10 @@ + + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml index 56610fc18ca..de160624064 100644 --- a/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml @@ -20,6 +20,13 @@ + + + + + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml index 53a3e5a8afc..9d74bce9c5c 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml @@ -81,7 +81,11 @@ + + + + + + + + diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml index 1c983db04a7..c7a4f001417 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml @@ -107,7 +107,11 @@ - + + + + + diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml index a743c32fa86..3b9d1ee724c 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml @@ -74,7 +74,11 @@ - + + + + + From 785f3fd91b88d984c8a8bbd319b8642ec2d043d1 Mon Sep 17 00:00:00 2001 From: Karishma Thakare Date: Mon, 29 Sep 2025 10:25:18 +0530 Subject: [PATCH 24/46] ACQE-8743: [ATLH] Product. Second round of update - Added product deletion code --- ...minManageStockForVirtualProductIsDisabledTest.xml | 1 + .../AdminUseDecimalQuantityOnSimpleProductTest.xml | 1 + .../AdminUseDecimalQuantityOnVirtualProductTest.xml | 1 + ...oductWithDropDownAttributeAndCustomSourceTest.xml | 2 ++ ...eProductToConfigurableProductCustomSourceTest.xml | 8 ++------ ...ionConfigurableProductSoldOutCustomStocksTest.xml | 5 +++-- ...ogQuickSearchForVirtualProductOnTestStockTest.xml | 1 + ...ctCustomStockMainWebsitePriceVerificationTest.xml | 12 +++--------- ...TextSwatchAttributeCustomStockMainWebsiteTest.xml | 12 +++--------- ...eProductWithSwatchAttributeMultipleStocksTest.xml | 3 ++- ...eOrderWithDownloadableProductDefaultStockTest.xml | 3 +++ ...ForOrderWithSimpleProductFromCustomSourceTest.xml | 2 ++ ...leProductWithDropDownAttributeViaTheAdminTest.xml | 3 +++ ...ableProductWithSwatchAttributeViaTheAdminTest.xml | 3 +++ ...ableProductWithSwatchAttributeViaTheAdminTest.xml | 3 +++ ...urableProductWithTextAttributeViaTheAdminTest.xml | 3 +++ ...dminAfterPartialInvoiceAndPartialShipmentTest.xml | 1 + ...aveTwiceDuringCreatingConfigurableProductTest.xml | 3 +++ .../Test/AdminUserSetStatusForEachSourceItemTest.xml | 1 + ...iceRuleConfigurableProductAdditionalStockTest.xml | 1 + 20 files changed, 42 insertions(+), 27 deletions(-) diff --git a/Inventory/Test/Mftf/Test/AdminManageStockForVirtualProductIsDisabledTest.xml b/Inventory/Test/Mftf/Test/AdminManageStockForVirtualProductIsDisabledTest.xml index 44d5dc0fe86..a7797a38d8c 100644 --- a/Inventory/Test/Mftf/Test/AdminManageStockForVirtualProductIsDisabledTest.xml +++ b/Inventory/Test/Mftf/Test/AdminManageStockForVirtualProductIsDisabledTest.xml @@ -67,6 +67,7 @@ + diff --git a/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnSimpleProductTest.xml b/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnSimpleProductTest.xml index 41287bdc125..37d1e94e898 100644 --- a/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnSimpleProductTest.xml +++ b/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnSimpleProductTest.xml @@ -44,6 +44,7 @@ + diff --git a/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnVirtualProductTest.xml b/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnVirtualProductTest.xml index ad0ed05f173..b7c481f5628 100644 --- a/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnVirtualProductTest.xml +++ b/Inventory/Test/Mftf/Test/AdminUseDecimalQuantityOnVirtualProductTest.xml @@ -44,6 +44,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminAddConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminAddConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml index 63b51f37395..7b17fa9080a 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminAddConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminAddConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml @@ -49,6 +49,8 @@ + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml index d127f7cb929..19f7b0d78d8 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml @@ -29,12 +29,8 @@ - - - - - - + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml index 51aa0939879..fdf2c13dfd9 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml @@ -45,10 +45,11 @@ - + - + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductOnTestStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductOnTestStockTest.xml index a0c71d5e431..39669f68cf9 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductOnTestStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCatalogQuickSearchForVirtualProductOnTestStockTest.xml @@ -40,6 +40,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminConfigurableProductCustomStockMainWebsitePriceVerificationTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminConfigurableProductCustomStockMainWebsitePriceVerificationTest.xml index cafa168d21c..23d02b18daf 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminConfigurableProductCustomStockMainWebsitePriceVerificationTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminConfigurableProductCustomStockMainWebsitePriceVerificationTest.xml @@ -38,15 +38,9 @@ - - - - - - - - - + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductTextSwatchAttributeCustomStockMainWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductTextSwatchAttributeCustomStockMainWebsiteTest.xml index 9ca27267aba..3533cd66e39 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductTextSwatchAttributeCustomStockMainWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductTextSwatchAttributeCustomStockMainWebsiteTest.xml @@ -32,15 +32,9 @@ - - - - - - - - - + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductWithSwatchAttributeMultipleStocksTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductWithSwatchAttributeMultipleStocksTest.xml index ad29ee310b3..bb4d4a1b0ab 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductWithSwatchAttributeMultipleStocksTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateConfigurableProductWithSwatchAttributeMultipleStocksTest.xml @@ -87,9 +87,10 @@ - + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateOrderWithDownloadableProductDefaultStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateOrderWithDownloadableProductDefaultStockTest.xml index bf53fc410aa..f69b63a72c7 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateOrderWithDownloadableProductDefaultStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateOrderWithDownloadableProductDefaultStockTest.xml @@ -66,6 +66,9 @@ + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreatePartialShipmentForOrderWithSimpleProductFromCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreatePartialShipmentForOrderWithSimpleProductFromCustomSourceTest.xml index e98aaaa43a3..d4b162c960c 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreatePartialShipmentForOrderWithSimpleProductFromCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreatePartialShipmentForOrderWithSimpleProductFromCustomSourceTest.xml @@ -84,6 +84,8 @@ + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml index 4fabd42c6bf..4c27136ea5a 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml @@ -53,6 +53,9 @@ + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml index 07e8e263b87..ef6de7a6a77 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml @@ -53,6 +53,9 @@ + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml index c526fb61670..1a83f07e3ac 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml @@ -55,6 +55,9 @@ + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml index 25e79d06b77..0497d61bbc1 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml @@ -55,6 +55,9 @@ + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderWithTwoSimpleProductsOnTestStockCanceledFromAdminAfterPartialInvoiceAndPartialShipmentTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderWithTwoSimpleProductsOnTestStockCanceledFromAdminAfterPartialInvoiceAndPartialShipmentTest.xml index 27c4b127969..e962464f0ad 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderWithTwoSimpleProductsOnTestStockCanceledFromAdminAfterPartialInvoiceAndPartialShipmentTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderWithTwoSimpleProductsOnTestStockCanceledFromAdminAfterPartialInvoiceAndPartialShipmentTest.xml @@ -54,6 +54,7 @@ + diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminSaveTwiceDuringCreatingConfigurableProductTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminSaveTwiceDuringCreatingConfigurableProductTest.xml index b35175e33cf..464eff76ea1 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminSaveTwiceDuringCreatingConfigurableProductTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminSaveTwiceDuringCreatingConfigurableProductTest.xml @@ -39,6 +39,9 @@ + + + + diff --git a/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml index cd7ab9c0933..57e5b996f36 100644 --- a/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/CatalogPriceRuleConfigurableProductAdditionalStockTest.xml @@ -70,6 +70,7 @@ + From 60fd1d3738ba05af9a28a552a7c6ade2a31fcd17 Mon Sep 17 00:00:00 2001 From: Karishma Thakare Date: Mon, 29 Sep 2025 13:46:49 +0530 Subject: [PATCH 25/46] ACQE-8743: [ATLH] Product. Second round of update - added product deletion code --- ...eProductToConfigurableProductCustomSourceTest.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml index 19f7b0d78d8..7ecf11c3a4c 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminAddSimpleProductToConfigurableProductCustomSourceTest.xml @@ -29,8 +29,12 @@ - - + + + + + + @@ -44,8 +48,8 @@ - - + + From 5e7077446461a3eb08a1e69ca775d0ae050299c7 Mon Sep 17 00:00:00 2001 From: glo5363 Date: Tue, 19 Aug 2025 18:45:24 +0530 Subject: [PATCH 26/46] ACQE-8275: [ATLH] Customers CE. Initial list of tests which do not delete customers - Fixes applied to remove customer data --- ...ForVirtualProductWithDefaultSourceTest.xml | 21 -------- ...oldForVirtualProductWithTestSourceTest.xml | 19 ------- ...StockThresholdOnVirtualProductPageTest.xml | 14 ----- ...rderConfigurableProductCustomStockTest.xml | 2 - ...igurableProductSoldOutCustomStocksTest.xml | 3 -- ...thDropDownAttributeAndCustomSourceTest.xml | 2 - ...dleProductCustomStockCustomWebsiteTest.xml | 3 +- ...onfigurableProductFromCustomSourceTest.xml | 2 - ...rderWithSimpleProductOnCustomStockTest.xml | 3 +- ...onfigurableProductFromCustomSourceTest.xml | 2 - ...nfigurableProductFromDefaultSourceTest.xml | 2 - ...ctWithDropDownAttributeViaTheAdminTest.xml | 46 +---------------- ...ductWithSwatchAttributeViaTheAdminTest.xml | 51 ++----------------- ...roductWithTextAttributeViaTheAdminTest.xml | 50 ++---------------- ...ductWithSwatchAttributeViaTheAdminTest.xml | 46 ----------------- ...roductWithTextAttributeViaTheAdminTest.xml | 46 ----------------- ...dleProductCustomStockCustomWebsiteTest.xml | 3 +- ...ncedInventorySettingsOnProductPageTest.xml | 13 ++--- ...roductOnTestStockFromCustomWebsiteTest.xml | 6 ++- ...InventorySettingsFromCustomWebsiteTest.xml | 4 -- ...ctAdditionalStockAdditionalWebsiteTest.xml | 8 +-- ...bleProductSoldOutInSingleStockModeTest.xml | 2 - ...tityConfigurableProductCustomStockTest.xml | 2 - ...tityConfigurableProductCustomStockTest.xml | 3 -- ...roductOnTestStockFromCustomWebsiteTest.xml | 15 +----- ...thDropDownAttributeAndCustomSourceTest.xml | 2 - ...hDropDownAttributeAndDefaultSourceTest.xml | 2 - ...rderedVirtualProductOnDefaultStockTest.xml | 13 ----- ...edPartialAndBackOrderedAccordinglyTest.xml | 23 --------- ...tomWebsiteBySkuFromCustomerAccountTest.xml | 4 -- ...pleProductCustomStockCustomWebsiteTest.xml | 8 ++- ...ntPageWithSimpleProductCustomStockTest.xml | 8 ++- 32 files changed, 32 insertions(+), 396 deletions(-) diff --git a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml index 595f2e49f87..9213ec3ea0d 100644 --- a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml +++ b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithDefaultSourceTest.xml @@ -18,22 +18,18 @@ - - - - @@ -41,9 +37,7 @@ - - @@ -74,22 +68,17 @@ - - - - - @@ -97,39 +86,29 @@ - - - - - - - - - - diff --git a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml index 9d3e1083ac6..995ee9d4479 100644 --- a/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml +++ b/Inventory/Test/Mftf/Test/AdminCanSetOnlyXLeftThresholdForVirtualProductWithTestSourceTest.xml @@ -18,24 +18,19 @@ - - - - - @@ -49,37 +44,30 @@ - - - - - - - @@ -87,29 +75,22 @@ - - - - - - - diff --git a/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml b/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml index 8425fb6d72c..0e49100c13e 100644 --- a/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml +++ b/Inventory/Test/Mftf/Test/AdminOutOfStockThresholdOnVirtualProductPageTest.xml @@ -19,25 +19,20 @@ - - - - - @@ -45,19 +40,14 @@ - - - - - @@ -66,21 +56,17 @@ - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml index 554a5ce003b..9841ea22775 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AddProductToCartAfterCancelOrderConfigurableProductCustomStockTest.xml @@ -18,7 +18,6 @@ - @@ -87,7 +86,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml index 8132f854dd8..e5f514a516b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml @@ -18,7 +18,6 @@ - @@ -54,7 +53,6 @@ - @@ -111,7 +109,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml index 8207fb196e9..ae95640b10b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCancelOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml @@ -18,7 +18,6 @@ - @@ -89,7 +88,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoAfterFullInvoiceFullShipmentBundleProductCustomStockCustomWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoAfterFullInvoiceFullShipmentBundleProductCustomStockCustomWebsiteTest.xml index f7ad6b447fb..16d7a9c3e4d 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoAfterFullInvoiceFullShipmentBundleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoAfterFullInvoiceFullShipmentBundleProductCustomStockCustomWebsiteTest.xml @@ -17,7 +17,6 @@ - @@ -112,12 +111,12 @@ + - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml index 2f174f8fe12..0d410e3b80b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCreditMemoWholeOrderWithConfigurableProductFromCustomSourceTest.xml @@ -18,7 +18,6 @@ - @@ -92,7 +91,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateFullInvoiceForOrderWithSimpleProductOnCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateFullInvoiceForOrderWithSimpleProductOnCustomStockTest.xml index 0bfb651596d..b8dc8ada88d 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateFullInvoiceForOrderWithSimpleProductOnCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateFullInvoiceForOrderWithSimpleProductOnCustomStockTest.xml @@ -17,7 +17,6 @@ - @@ -51,12 +50,12 @@ + - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml index af682627842..ddd8693e26b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromCustomSourceTest.xml @@ -18,7 +18,6 @@ - @@ -95,7 +94,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml index 68b626c9412..6dbf65d6cb9 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateShipmentForWholeOrderWithConfigurableProductFromDefaultSourceTest.xml @@ -18,7 +18,6 @@ - @@ -72,7 +71,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml index 4fabd42c6bf..faeb72b2d07 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithDropDownAttributeViaTheAdminTest.xml @@ -18,7 +18,6 @@ - @@ -27,7 +26,6 @@ - @@ -44,7 +42,6 @@ - @@ -58,48 +55,37 @@ + - - - - - - - - - - - - @@ -107,105 +93,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml index 07e8e263b87..d98d05e868a 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml @@ -18,17 +18,14 @@ - - - @@ -45,7 +42,6 @@ - @@ -53,81 +49,69 @@ + + + + - - - - - - - - - - - - - - - - @@ -136,102 +120,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithTextAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithTextAttributeViaTheAdminTest.xml index fc045bdc3c3..ff2ae913b6b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithTextAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithTextAttributeViaTheAdminTest.xml @@ -20,7 +20,6 @@ - @@ -28,12 +27,10 @@ - - @@ -44,71 +41,61 @@ + + + + - - - - - - - - - - - - - - @@ -116,102 +103,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml index 0560a8863ee..850bd97fc07 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml @@ -20,7 +20,6 @@ - @@ -29,7 +28,6 @@ - @@ -46,7 +44,6 @@ - @@ -59,67 +56,52 @@ - - - - - - - - - - - - - - - @@ -127,100 +109,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml index a98c8ac7974..11da69487e1 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedWithConfigurableProductWithTextAttributeViaTheAdminTest.xml @@ -20,7 +20,6 @@ - @@ -29,7 +28,6 @@ - @@ -46,7 +44,6 @@ - @@ -59,68 +56,53 @@ - - - - - - - - - - - - - - - @@ -128,100 +110,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminReorderBundleProductCustomStockCustomWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminReorderBundleProductCustomStockCustomWebsiteTest.xml index bb06a65f804..ab5a130b67b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminReorderBundleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminReorderBundleProductCustomStockCustomWebsiteTest.xml @@ -17,7 +17,6 @@ - @@ -112,12 +111,12 @@ + - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderFromCustomWebsiteWithSimpleProductWithManageStockNoInAdvancedInventorySettingsOnProductPageTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderFromCustomWebsiteWithSimpleProductWithManageStockNoInAdvancedInventorySettingsOnProductPageTest.xml index 9999fd0d859..33200a0f9ed 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderFromCustomWebsiteWithSimpleProductWithManageStockNoInAdvancedInventorySettingsOnProductPageTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderFromCustomWebsiteWithSimpleProductWithManageStockNoInAdvancedInventorySettingsOnProductPageTest.xml @@ -18,7 +18,6 @@ - @@ -29,7 +28,6 @@ - @@ -70,6 +68,10 @@ + + + + @@ -80,38 +82,31 @@ - - - - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml index c1a14f961a2..36862854c09 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml @@ -79,7 +79,10 @@ - + + + + @@ -87,7 +90,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml index 8fc1f5b0751..aba6691bf7f 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminUserCreateOrderWithSimpleProductWithManageStockNoInAdvancedInventorySettingsFromCustomWebsiteTest.xml @@ -23,10 +23,6 @@ - - - - diff --git a/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml index de160624064..bf943a75b8e 100644 --- a/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/RegisteredCustomerCreateOrderWithSimpleProductAdditionalStockAdditionalWebsiteTest.xml @@ -19,14 +19,14 @@ - - + + - + + - diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml index 2989d775aea..c519e96dffa 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontCacheValidationConfigurableProductSoldOutInSingleStockModeTest.xml @@ -18,7 +18,6 @@ - @@ -63,7 +62,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml index cb974fe53da..63c5b2c9508 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontCreateOrderAllQuantityConfigurableProductCustomStockTest.xml @@ -17,7 +17,6 @@ - @@ -84,7 +83,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml index 1b34e45a3ea..9ab991d7e96 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderAllOptionQuantityConfigurableProductCustomStockTest.xml @@ -17,7 +17,6 @@ - @@ -112,7 +111,6 @@ - @@ -133,7 +131,6 @@ - productOptions diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml index 9d74bce9c5c..d7ea5ab351b 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductOnTestStockFromCustomWebsiteTest.xml @@ -18,14 +18,12 @@ - - @@ -37,7 +35,6 @@ - @@ -52,7 +49,6 @@ - @@ -81,11 +77,9 @@ - - - - + + - @@ -104,18 +97,15 @@ - - - @@ -131,7 +121,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml index 911ca0055d7..f70ad56dc74 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndCustomSourceTest.xml @@ -18,7 +18,6 @@ - @@ -89,7 +88,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml index 624489d23c5..5a4acb4e16c 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderConfigurableProductWithDropDownAttributeAndDefaultSourceTest.xml @@ -18,7 +18,6 @@ - @@ -78,7 +77,6 @@ - diff --git a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml index cff084d6c2e..4cd398e60f9 100644 --- a/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/StorefrontLoggedInCustomerOrderedVirtualProductOnDefaultStockTest.xml @@ -18,16 +18,13 @@ - - - @@ -38,7 +35,6 @@ - @@ -54,17 +50,14 @@ - - - @@ -74,16 +67,12 @@ - - - - @@ -99,14 +88,12 @@ - - diff --git a/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml b/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml index 918bfd09fd0..d56caf73fa5 100644 --- a/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/ValidateAfterPlacingAnOrderWithZeroStatusAsOrderedPartialAndBackOrderedAccordinglyTest.xml @@ -18,7 +18,6 @@ - @@ -27,7 +26,6 @@ - @@ -35,7 +33,6 @@ - @@ -46,11 +43,9 @@ - - @@ -61,7 +56,6 @@ - @@ -71,18 +65,15 @@ - - - @@ -90,7 +81,6 @@ - @@ -99,7 +89,6 @@ - @@ -125,12 +114,10 @@ - - @@ -147,23 +134,18 @@ - - - - - @@ -171,7 +153,6 @@ - @@ -188,7 +169,6 @@ - @@ -199,7 +179,6 @@ - @@ -207,7 +186,6 @@ - @@ -215,7 +193,6 @@ - diff --git a/InventoryAdvancedCheckout/Test/Mftf/Test/CreateOrderWithConfigurableProductCustomStockCustomWebsiteBySkuFromCustomerAccountTest.xml b/InventoryAdvancedCheckout/Test/Mftf/Test/CreateOrderWithConfigurableProductCustomStockCustomWebsiteBySkuFromCustomerAccountTest.xml index cbfacb54de8..93e91dfbd7a 100644 --- a/InventoryAdvancedCheckout/Test/Mftf/Test/CreateOrderWithConfigurableProductCustomStockCustomWebsiteBySkuFromCustomerAccountTest.xml +++ b/InventoryAdvancedCheckout/Test/Mftf/Test/CreateOrderWithConfigurableProductCustomStockCustomWebsiteBySkuFromCustomerAccountTest.xml @@ -92,11 +92,7 @@ - - - - diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml index c7a4f001417..8e3cc4f33ae 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml @@ -17,7 +17,6 @@ - @@ -107,17 +106,16 @@ - + + - + - - diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml index 3b9d1ee724c..eac9ae32656 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontReviewAndPaymentPageWithSimpleProductCustomStockTest.xml @@ -17,7 +17,6 @@ - @@ -74,17 +73,16 @@ - + + - + - - From 83f10b83b1be1605fbe52eb375ee2d82508a9782 Mon Sep 17 00:00:00 2001 From: syed sharuk Date: Tue, 30 Sep 2025 14:38:20 +0530 Subject: [PATCH 27/46] ACQE-6820: Admin creates category, 22 sources via UI, and assigns all sources to simple product - Created test file and helper class --- .../Mftf/Helper/MultipleSourcesHelper.php | 114 ++++++++++++++ ...gnMultipleSourcesUIToSimpleProductTest.xml | 144 ++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php create mode 100644 InventoryAdminUi/Test/Mftf/Test/AdminCreateCategoryAndAssignMultipleSourcesUIToSimpleProductTest.xml diff --git a/Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php b/Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php new file mode 100644 index 00000000000..79da2b713c1 --- /dev/null +++ b/Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php @@ -0,0 +1,114 @@ + $sourceCode, + 'name' => $sourceName, + 'enabled' => 1, + 'description' => 'Test source ' . $i . ' created via helper', + 'latitude' => 40.7128 + ($i * 0.01), + 'longitude' => -74.0060 + ($i * 0.01), + 'country_id' => 'US', + 'region_id' => 43, + 'region' => 'New York', + 'city' => 'New York', + 'street' => 'Test Street ' . $i, + 'postcode' => '1000' . sprintf('%02d', $i), + 'contact_name' => 'Test Contact ' . $i, + 'email' => 'test' . $i . '@example.com', + 'phone' => '555-000-' . sprintf('%04d', $i), + 'fax' => '555-001-' . sprintf('%04d', $i), + 'use_default_carrier_config' => 1 + ], + [], + null + ); + + // Create CurlHandler for source creation using MFTF pattern + $curlHandler = ObjectManagerFactory::getObjectManager()->create( + CurlHandler::class, + [ + 'operation' => 'create', + 'entityObject' => $sourceEntity, + 'storeCode' => null + ] + ); + + // Execute using MFTF CurlHandler + $response = $curlHandler->executeRequest([]); + + if (is_array($response) && isset($response['source_code'])) { + $createdSources[] = [ + 'source_code' => $response['source_code'], + 'name' => $response['name'] ?? $sourceName, + 'source_id' => $response['source_code'] + ]; + } else { + // If API creation fails, still add to list for test continuity + $createdSources[] = [ + 'source_code' => $sourceCode, + 'name' => $sourceName, + 'source_id' => $sourceCode + ]; + } + } catch (\Exception $e) { + // If creation fails, still add to list for test continuity + $createdSources[] = [ + 'source_code' => $sourceCode, + 'name' => $sourceName, + 'source_id' => $sourceCode + ]; + } + } + + return $createdSources; + } + + + /** + * Get source codes from created sources array + * + * @param array $createdSources Array returned from createMultipleSources + * @return array Array of source codes + */ + public function extractSourceCodes(array $createdSources): array + { + return array_column($createdSources, 'source_code'); + } +} diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCreateCategoryAndAssignMultipleSourcesUIToSimpleProductTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCategoryAndAssignMultipleSourcesUIToSimpleProductTest.xml new file mode 100644 index 00000000000..725f79ca0f3 --- /dev/null +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCreateCategoryAndAssignMultipleSourcesUIToSimpleProductTest.xml @@ -0,0 +1,144 @@ + + + + + + + + + + <description value="Verify admin can create category, create 22 sources through UI with address data, create simple product, and assign all 22 sources plus default source to the product"/> + <severity value="MAJOR"/> + <testCaseId value="AC-6556"/> + <group value="msi"/> + </annotations> + <before> + <!-- Step 1: Create category --> + <createData entity="SimpleSubCategory" stepKey="createCategory"/> + <!-- Step 2-3: Create 22 Sources using Helper --> + <helper class="Magento\Inventory\Test\Mftf\Helper\MultipleSourcesHelper" method="createMultipleSources" stepKey="createMultipleSources"> + <argument name="count">22</argument> + <argument name="prefix">TestSource</argument> + </helper> + <!-- Step 4: Create product --> + <createData entity="SimpleProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + <deleteData createDataKey="createProduct" stepKey="deleteProduct"/> + <!-- Disable all created sources --> + <actionGroup ref="DisableAllSourcesActionGroup" stepKey="disableAllSources"/> + <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutFromAdmin"/> + </after> + <!-- Step 5: Verify product in grid --> + <actionGroup ref="AdminOpenProductIndexPageActionGroup" stepKey="navigateToProductIndex"/> + <actionGroup ref="FilterProductGridByNameActionGroup" stepKey="filterProduct"> + <argument name="product" value="$$createProduct$$"/> + </actionGroup> + <!-- Verify product appears in grid --> + <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="verifyProductNameInGrid"> + <argument name="column" value="Name"/> + <argument name="value" value="$createProduct.name$"/> + </actionGroup> + <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="verifyProductSkuInGrid"> + <argument name="column" value="SKU"/> + <argument name="value" value="$createProduct.sku$"/> + </actionGroup> + <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="verifyProductPriceInGrid"> + <argument name="column" value="Price"/> + <argument name="value" value="$123.00"/> + </actionGroup> + <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="verifyProductStatusInGrid"> + <argument name="column" value="Status"/> + <argument name="value" value="Enabled"/> + </actionGroup> + <actionGroup ref="AssertAdminProductGridCellActionGroup" stepKey="verifyProductWebsiteInGrid"> + <argument name="column" value="Websites"/> + <argument name="value" value="Main Website"/> + </actionGroup> + <!-- Step 6: Assign all 22 sources to product --> + <click selector="{{AdminProductGridSection.productGridNameProduct($$createProduct.product[name]$$)}}" stepKey="clickProductToEdit"/> + <waitForPageLoad stepKey="waitForProductEditPageLoad"/> + <!-- Assign sources using bulk selection --> + <click selector="{{AdminProductSourcesSection.assignSources}}" stepKey="clickAssignMoreSources"/> + <waitForPageLoad stepKey="waitForSourcesModal"/> + <!-- Set pagination to show 30 sources --> + <actionGroup ref="AdminDataGridSelectPerPageActionGroup" stepKey="selectShow30Sources"> + <argument name="perPage" value="30"/> + </actionGroup> + <actionGroup ref="AdminClearGridFiltersActionGroup" stepKey="clearFilters"/> + <!-- Use bulk selection to select all available sources --> + <click selector="{{AdminGridSelectRows.multicheckDropdown}}" stepKey="openMultiCheckDropdown"/> + <click selector="{{AdminGridSelectRows.multicheckOption('Select All')}}" stepKey="selectAllAvailableSources"/> + <waitForPageLoad stepKey="waitAfterSelectAll"/> + <!-- Click Done --> + <click selector="{{AdminAssignSourcesSlideOutSection.done}}" stepKey="clickDoneAfterSelectingSources"/> + <!-- Verify sources were assigned successfully --> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('1')}}" stepKey="waitForSourcesInGrid"/> + <!-- Step 7: Set quantity for a few sources to verify functionality --> + <fillField selector="{{AdminProductSourcesGrid.rowQty('0')}}" userInput="100" stepKey="setDefaultSourceQuantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('1')}}" userInput="100" stepKey="setSource1Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('2')}}" userInput="100" stepKey="setSource2Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('3')}}" userInput="100" stepKey="setSource3Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('4')}}" userInput="100" stepKey="setSource4Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('5')}}" userInput="100" stepKey="setSource5Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('6')}}" userInput="100" stepKey="setSource6Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('7')}}" userInput="100" stepKey="setSource7Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('8')}}" userInput="100" stepKey="setSource8Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('9')}}" userInput="100" stepKey="setSource9Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('10')}}" userInput="100" stepKey="setSource10Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('11')}}" userInput="100" stepKey="setSource11Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('12')}}" userInput="100" stepKey="setSource12Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('13')}}" userInput="100" stepKey="setSource13Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('14')}}" userInput="100" stepKey="setSource14Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('15')}}" userInput="100" stepKey="setSource15Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('16')}}" userInput="100" stepKey="setSource16Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('17')}}" userInput="100" stepKey="setSource17Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('18')}}" userInput="100" stepKey="setSource18Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQty('19')}}" userInput="100" stepKey="setSource19Quantity"/> + <scrollTo selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="scrollToNextPageSourcesGrid"/> + <waitForElementClickable selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="waitForNextPageClickable"/> + <executeJS function="document.querySelector('{{AdminDataGridPaginationSection.nextPage}}').click();" stepKey="clickNextPageViaJS"/> + <waitForPageLoad stepKey="waitForNextPageLoad"/> + <fillField selector="{{AdminProductSourcesGrid.rowQtyCustom('0', '20')}}" userInput="100" stepKey="setSource20Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQtyCustom('1', '21')}}" userInput="100" stepKey="setSource21Quantity"/> + <fillField selector="{{AdminProductSourcesGrid.rowQtyCustom('2', '22')}}" userInput="100" stepKey="setSource22Quantity"/> + <!-- Step 8: Save product--> + <actionGroup ref="AdminProductFormSaveActionGroup" stepKey="saveProductWithAllSources"/> + <!-- Step 9: Verify sources were added correctly --> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('0')}}" stepKey="verifyDefaultSourcePresent"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('1')}}" stepKey="verifySource1Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('2')}}" stepKey="verifySource2Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('3')}}" stepKey="verifySource3Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('4')}}" stepKey="verifySource4Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('5')}}" stepKey="verifySource5Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('6')}}" stepKey="verifySource6Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('7')}}" stepKey="verifySource7Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('8')}}" stepKey="verifySource8Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('9')}}" stepKey="verifySource9Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('10')}}" stepKey="verifySource10Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('11')}}" stepKey="verifySource11Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('12')}}" stepKey="verifySource12Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('13')}}" stepKey="verifySource13Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('14')}}" stepKey="verifySource14Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('15')}}" stepKey="verifySource15Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('16')}}" stepKey="verifySource16Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('17')}}" stepKey="verifySource17Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('18')}}" stepKey="verifySource18Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('19')}}" stepKey="verifySource19Present"/> + <waitForElementClickable selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="waitForNextPageClickableAgain"/> + <executeJS function="document.querySelector('{{AdminDataGridPaginationSection.nextPage}}').click();" stepKey="clickNextPageViaJSAgain"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('0')}}" stepKey="verifySource20Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('1')}}" stepKey="verifySource21Present"/> + <waitForElementVisible selector="{{AdminProductSourcesGrid.rowByIndex('2')}}" stepKey="verifySource22Present"/> + </test> +</tests> From 5fb1dd3f2d1d0629f32a8cf6c6d2591793ba7bf5 Mon Sep 17 00:00:00 2001 From: syed sharuk <glo74186@adobe.com> Date: Tue, 30 Sep 2025 14:41:02 +0530 Subject: [PATCH 28/46] ACQE-6820: Admin creates category, 22 sources via UI, and assigns all sources to simple product - Created element --- .../AdminProductSourcesGridSection.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/InventoryAdminUi/Test/Mftf/Section/AdminProductSourcesFormSection/AdminProductSourcesGridSection.xml b/InventoryAdminUi/Test/Mftf/Section/AdminProductSourcesFormSection/AdminProductSourcesGridSection.xml index 30dd08e027d..a8dd31015a3 100644 --- a/InventoryAdminUi/Test/Mftf/Section/AdminProductSourcesFormSection/AdminProductSourcesGridSection.xml +++ b/InventoryAdminUi/Test/Mftf/Section/AdminProductSourcesFormSection/AdminProductSourcesGridSection.xml @@ -16,6 +16,7 @@ <element name="rowStatus" type="button" selector=".data-row[data-repeat-index='{{arg1}}'] select[name='sources[assigned_sources][{{arg1}}][status]']" parameterized="true"/> <element name="rowStatusBySourceCode" type="select" selector="//span[@data-index='name'][contains(@title, '{{sourceCode}}')]/following::select[contains(@name, '[status]')]" parameterized="true"/> <element name="rowQty" type="button" selector=".data-row[data-repeat-index='{{arg1}}'] input[name='sources[assigned_sources][{{arg1}}][quantity]']" parameterized="true"/> + <element name="rowQtyCustom" type="input" selector=".data-row[data-repeat-index='{{arg1}}'] input[name='sources[assigned_sources][{{arg2}}][quantity]']" parameterized="true"/> <element name="rowQtyBySourceCode" type="input" selector="//span[@data-index='name'][contains(@title, '{{sourceCode}}')]/following::input[contains(@name, '[quantity]')]" parameterized="true"/> <element name="rowNotifyQuantity" type="button" selector=".data-row[data-repeat-index='{{arg1}}'] input[name='sources[assigned_sources][{{arg1}}][notify_stock_qty]']" parameterized="true"/> <element name="rowUnAssign" type="button" selector=".data-row[data-repeat-index='{{arg1}}'] button[data-action='remove_row']" parameterized="true"/> From 51ee5806ce03b8d2b60bdcc6bf791a3ffdf2d26c Mon Sep 17 00:00:00 2001 From: Sokly Meach <meach@adobe.com> Date: Tue, 30 Sep 2025 16:26:58 -0500 Subject: [PATCH 29/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../AdminNotifyCustomerForPickupOrderBundleProductTest.xml | 4 ---- ...minNotifyCustomerForPickupOrderConfigurableProductTest.xml | 4 ---- .../AdminNotifyCustomerForPickupOrderGroupedProductTest.xml | 4 ---- ...eateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml | 4 ---- 4 files changed, 16 deletions(-) diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml index b9d0ab73e78..05c0bd6614a 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml @@ -114,10 +114,6 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> - <argument name="customerVar" value="Simple_US_Customer"/> - <argument name="customerAddressVar" value="US_Address_TX"/> - </actionGroup> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml index b8774508aa2..85257725876 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml @@ -114,10 +114,6 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> - <argument name="customerVar" value="Simple_US_Customer"/> - <argument name="customerAddressVar" value="US_Address_TX"/> - </actionGroup> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml index 654aa21c8d3..2bb5d926f3d 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml @@ -115,10 +115,6 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> - <argument name="customerVar" value="Simple_US_Customer"/> - <argument name="customerAddressVar" value="US_Address_TX"/> - </actionGroup> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml index 1c983db04a7..f640beef598 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml @@ -132,10 +132,6 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> - <argument name="customerVar" value="Simple_US_Customer"/> - <argument name="customerAddressVar" value="US_Address_TX"/> - </actionGroup> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> <waitForPageLoad stepKey="waitForSuccess"/> From 34e31a352718d66ff07288f7cec5e6f21db1213d Mon Sep 17 00:00:00 2001 From: Sokly Meach <meach@adobe.com> Date: Tue, 30 Sep 2025 18:14:46 -0500 Subject: [PATCH 30/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- .../Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml | 1 + .../AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml | 1 + .../Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml | 1 + ...rCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml | 1 + 4 files changed, 4 insertions(+) diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml index 05c0bd6614a..3c3efc9aad5 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml @@ -114,6 +114,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> + <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml index 85257725876..8cc03868df7 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml @@ -114,6 +114,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> + <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml index 2bb5d926f3d..c1f48075df8 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml @@ -115,6 +115,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> + <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml index f640beef598..dd56c24b332 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml @@ -132,6 +132,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> + <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> <waitForPageLoad stepKey="waitForSuccess"/> From 69ac57d71a310687c5abd1f39bf4264abf46ab35 Mon Sep 17 00:00:00 2001 From: Sokly Meach <meach@adobe.com> Date: Tue, 30 Sep 2025 20:21:08 -0500 Subject: [PATCH 31/46] ACP2E-4030: Missing billing address prevents order placing with 'In store Delivery' shipping method --- ...eOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml index d3905ebbf0b..b2e57984ed8 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml @@ -132,10 +132,7 @@ <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="clickCheckMoneyOrderPayment"/> <!--Fill Shipping address --> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> - <argument name="customerVar" value="Simple_US_Customer"/> - <argument name="customerAddressVar" value="US_Address_TX"/> - </actionGroup> + <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> <!--Click on place order --> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> <waitForElement selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="waitForOrderNumber"/> From 52f04244b0c2bec2d80f05e3705ee189783a4a9d Mon Sep 17 00:00:00 2001 From: syed sharuk <glo74186@adobe.com> Date: Mon, 6 Oct 2025 14:56:18 +0530 Subject: [PATCH 32/46] ACQE-6820: Admin creates category, 22 sources via UI, and assigns all sources to simple product - Set proper indentation in helper file --- .../Mftf/Helper/MultipleSourcesHelper.php | 175 +++++++++--------- 1 file changed, 87 insertions(+), 88 deletions(-) diff --git a/Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php b/Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php index 79da2b713c1..063e0a4eb4c 100644 --- a/Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php +++ b/Inventory/Test/Mftf/Helper/MultipleSourcesHelper.php @@ -7,9 +7,9 @@ namespace Magento\Inventory\Test\Mftf\Helper; -use Magento\FunctionalTestingFramework\Helper\Helper; -use Magento\FunctionalTestingFramework\DataGenerator\Persist\CurlHandler; use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; +use Magento\FunctionalTestingFramework\DataGenerator\Persist\CurlHandler; +use Magento\FunctionalTestingFramework\Helper\Helper; use Magento\FunctionalTestingFramework\ObjectManagerFactory; /** @@ -17,98 +17,97 @@ */ class MultipleSourcesHelper extends Helper { - /** - * Create multiple sources programmatically using MFTF CurlHandler - * - * @param int $count Number of sources to create - * @param string $prefix Prefix for source codes and names - * @return array Array of created source data - */ - public function createMultipleSources(int $count = 22, string $prefix = 'TestSource'): array - { - $createdSources = []; + /** + * Create multiple sources programmatically using MFTF CurlHandler + * + * @param int $count + * @param string $prefix + * @return array[] + */ + public function createMultipleSources(int $count = 22, string $prefix = 'TestSource'): array + { + $createdSources = []; - for ($i = 1; $i <= $count; $i++) { - $sourceCode = $prefix . $i; - $sourceName = $prefix . ' ' . $i; + for ($i = 1; $i <= $count; $i++) { + $sourceCode = $prefix . $i; + $sourceName = $prefix . ' ' . $i; - try { - // Create EntityDataObject for source creation using MFTF pattern - $sourceEntity = new EntityDataObject( - 'source_' . $sourceCode, - 'source', - [ - 'source_code' => $sourceCode, - 'name' => $sourceName, - 'enabled' => 1, - 'description' => 'Test source ' . $i . ' created via helper', - 'latitude' => 40.7128 + ($i * 0.01), - 'longitude' => -74.0060 + ($i * 0.01), - 'country_id' => 'US', - 'region_id' => 43, - 'region' => 'New York', - 'city' => 'New York', - 'street' => 'Test Street ' . $i, - 'postcode' => '1000' . sprintf('%02d', $i), - 'contact_name' => 'Test Contact ' . $i, - 'email' => 'test' . $i . '@example.com', - 'phone' => '555-000-' . sprintf('%04d', $i), - 'fax' => '555-001-' . sprintf('%04d', $i), - 'use_default_carrier_config' => 1 - ], - [], - null - ); + try { + // Create EntityDataObject for source creation using MFTF pattern + $sourceEntity = new EntityDataObject( + 'source_' . $sourceCode, + 'source', + [ + 'source_code' => $sourceCode, + 'name' => $sourceName, + 'enabled' => 1, + 'description' => 'Test source ' . $i . ' created via helper', + 'latitude' => 40.7128 + ($i * 0.01), + 'longitude' => -74.0060 + ($i * 0.01), + 'country_id' => 'US', + 'region_id' => 43, + 'region' => 'New York', + 'city' => 'New York', + 'street' => 'Test Street ' . $i, + 'postcode' => '1000' . sprintf('%02d', $i), + 'contact_name' => 'Test Contact ' . $i, + 'email' => 'test' . $i . '@example.com', + 'phone' => '555-000-' . sprintf('%04d', $i), + 'fax' => '555-001-' . sprintf('%04d', $i), + 'use_default_carrier_config' => 1 + ], + [], + null + ); - // Create CurlHandler for source creation using MFTF pattern - $curlHandler = ObjectManagerFactory::getObjectManager()->create( - CurlHandler::class, - [ - 'operation' => 'create', - 'entityObject' => $sourceEntity, - 'storeCode' => null - ] - ); + // Create CurlHandler for source creation using MFTF pattern + $curlHandler = ObjectManagerFactory::getObjectManager()->create( + CurlHandler::class, + [ + 'operation' => 'create', + 'entityObject' => $sourceEntity, + 'storeCode' => null + ] + ); - // Execute using MFTF CurlHandler - $response = $curlHandler->executeRequest([]); + // Execute using MFTF CurlHandler + $response = $curlHandler->executeRequest([]); - if (is_array($response) && isset($response['source_code'])) { - $createdSources[] = [ - 'source_code' => $response['source_code'], - 'name' => $response['name'] ?? $sourceName, - 'source_id' => $response['source_code'] - ]; - } else { - // If API creation fails, still add to list for test continuity - $createdSources[] = [ - 'source_code' => $sourceCode, - 'name' => $sourceName, - 'source_id' => $sourceCode - ]; + if (is_array($response) && isset($response['source_code'])) { + $createdSources[] = [ + 'source_code' => $response['source_code'], + 'name' => $response['name'] ?? $sourceName, + 'source_id' => $response['source_code'] + ]; + } else { + // If API creation fails, still add to list for test continuity + $createdSources[] = [ + 'source_code' => $sourceCode, + 'name' => $sourceName, + 'source_id' => $sourceCode + ]; + } + } catch (\Exception $e) { + // If creation fails, still add to list for test continuity + $createdSources[] = [ + 'source_code' => $sourceCode, + 'name' => $sourceName, + 'source_id' => $sourceCode + ]; + } } - } catch (\Exception $e) { - // If creation fails, still add to list for test continuity - $createdSources[] = [ - 'source_code' => $sourceCode, - 'name' => $sourceName, - 'source_id' => $sourceCode - ]; - } - } - - return $createdSources; - } + return $createdSources; + } - /** - * Get source codes from created sources array - * - * @param array $createdSources Array returned from createMultipleSources - * @return array Array of source codes - */ - public function extractSourceCodes(array $createdSources): array - { - return array_column($createdSources, 'source_code'); - } + /** + * Get source codes from created sources array + * + * @param array[] $createdSources + * @return string[] + */ + public function extractSourceCodes(array $createdSources): array + { + return array_column($createdSources, 'source_code'); + } } From 79f57d79627137bca4d528405d9f9bd24237573a Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <dhorytskyi@magento.com> Date: Mon, 6 Oct 2025 12:36:30 -0500 Subject: [PATCH 33/46] ACP2E-4233: Grouped product incorrectly shows as Out of Stock on PDP after import from CSV when child is assigned to custom source/stock (fixed after manual reindex) --- .../Indexer/OptionsStatusSelectBuilder.php | 56 +-- .../Indexer/SelectBuilder.php | 6 +- .../Indexer/SiblingProductsProvider.php | 16 - .../Indexer/StockIndexer.php | 141 ------- ...urceItemsAfterAddBundleSelectionPlugin.php | 39 +- ...ItemsAfterBulkAddBundleSelectionPlugin.php | 39 +- ...eItemsAfterRemoveBundleSelectionPlugin.php | 39 +- ...rceItemsAfterSaveBundleSelectionPlugin.php | 39 +- .../Integration/Indexer/StockIndexerTest.php | 21 +- InventoryBundleProductIndexer/etc/di.xml | 13 +- .../Model/GetChildrenSkusOfParentSkus.php | 57 +++ .../Model/GetChildrenSkusOfParentSkusTest.php | 79 ++++ InventoryCatalog/etc/di.xml | 1 + .../GetChildrenSkusOfParentSkusInterface.php | 31 ++ .../Indexer/SelectBuilder.php | 43 +- .../Indexer/SiblingProductsProvider.php | 16 - .../SiblingSkuListInStockProvider.php | 147 ------- .../Indexer/SourceItem/SourceItemIndexer.php | 160 -------- .../Sync/APISourceItemIndexerPlugin.php | 90 ++--- ...ProviderTest.php => SelectBuilderTest.php} | 38 +- .../Sync/APISourceItemIndexerPluginTest.php | 105 +++-- .../etc/di.xml | 19 +- .../Indexer/SelectBuilder.php | 36 +- .../Indexer/SiblingProductsProvider.php | 16 - InventoryGroupedProductIndexer/etc/di.xml | 8 +- .../Plugin/Import/SourceItemImporter.php | 9 +- .../Integration/Model/Import/ProductTest.php | 52 ++- .../Plugin/Import/SourceItemImporterTest.php | 32 +- .../Indexer/CompositeProductsIndexer.php | 85 ++++ .../SiblingProductsProviderInterface.php | 11 - .../Indexer/SiblingProductsProvidersPool.php | 46 +++ .../Indexer/SiblingSelectBuilderInterface.php | 9 +- .../Indexer/SourceItem/GetSkuListInStock.php | 4 +- .../Indexer/SourceItem/SkuListInStock.php | 14 +- .../Indexer/Stock/DataProvider.php | 67 ++++ .../Indexer/Stock/IndexDataFiller.php | 111 +++--- .../Indexer/Stock/SkuListsProcessor.php | 26 +- .../Indexer/Stock/Strategy/Sync.php | 105 ++--- .../Indexer/CompositeProductsIndexerTest.php | 138 +++++++ .../SiblingProductsProvidersPoolTest.php | 50 +++ .../Indexer/SourceItem/SkuListInStockTest.php | 27 ++ .../Unit/Indexer/Stock/DataProviderTest.php | 103 +++++ .../Indexer/Stock/IndexDataFillerTest.php | 373 ++++++++++++++++++ .../Model/Alias.php | 23 +- .../Model/IndexAlias.php | 17 + 45 files changed, 1497 insertions(+), 1060 deletions(-) delete mode 100644 InventoryBundleProductIndexer/Indexer/StockIndexer.php create mode 100644 InventoryCatalog/Model/GetChildrenSkusOfParentSkus.php create mode 100644 InventoryCatalog/Test/Unit/Model/GetChildrenSkusOfParentSkusTest.php create mode 100644 InventoryCatalogApi/Model/GetChildrenSkusOfParentSkusInterface.php delete mode 100644 InventoryConfigurableProductIndexer/Indexer/SourceItem/SiblingSkuListInStockProvider.php delete mode 100644 InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php rename InventoryConfigurableProductIndexer/Test/Integration/Indexer/{SiblingProductsProviderTest.php => SelectBuilderTest.php} (54%) create mode 100644 InventoryIndexer/Indexer/CompositeProductsIndexer.php create mode 100644 InventoryIndexer/Indexer/SiblingProductsProvidersPool.php create mode 100644 InventoryIndexer/Indexer/Stock/DataProvider.php create mode 100644 InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php create mode 100644 InventoryIndexer/Test/Unit/Indexer/SiblingProductsProvidersPoolTest.php create mode 100644 InventoryIndexer/Test/Unit/Indexer/SourceItem/SkuListInStockTest.php create mode 100644 InventoryIndexer/Test/Unit/Indexer/Stock/DataProviderTest.php create mode 100644 InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php create mode 100644 InventoryMultiDimensionalIndexerApi/Model/IndexAlias.php diff --git a/InventoryBundleProductIndexer/Indexer/OptionsStatusSelectBuilder.php b/InventoryBundleProductIndexer/Indexer/OptionsStatusSelectBuilder.php index dcd61dad236..5ca733dfaab 100644 --- a/InventoryBundleProductIndexer/Indexer/OptionsStatusSelectBuilder.php +++ b/InventoryBundleProductIndexer/Indexer/OptionsStatusSelectBuilder.php @@ -13,67 +13,45 @@ use Magento\Framework\EntityManager\MetadataPool; use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryConfigurationApi\Model\InventoryConfigurationInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; +use Magento\InventoryIndexer\Indexer\InventoryIndexer; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameResolverInterface; class OptionsStatusSelectBuilder { - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var IndexNameResolverInterface - */ - private $indexNameResolver; - - /** - * @var MetadataPool - */ - private $metadataPool; - - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - - /** - * @var InventoryConfigurationInterface - */ - private $inventoryConfiguration; - /** * @param ResourceConnection $resourceConnection + * @param IndexNameBuilder $indexNameBuilder * @param IndexNameResolverInterface $indexNameResolver * @param MetadataPool $metadataPool * @param DefaultStockProviderInterface $defaultStockProvider * @param InventoryConfigurationInterface $inventoryConfiguration */ public function __construct( - ResourceConnection $resourceConnection, - IndexNameResolverInterface $indexNameResolver, - MetadataPool $metadataPool, - DefaultStockProviderInterface $defaultStockProvider, - InventoryConfigurationInterface $inventoryConfiguration + private readonly ResourceConnection $resourceConnection, + private readonly IndexNameBuilder $indexNameBuilder, + private readonly IndexNameResolverInterface $indexNameResolver, + private readonly MetadataPool $metadataPool, + private readonly DefaultStockProviderInterface $defaultStockProvider, + private readonly InventoryConfigurationInterface $inventoryConfiguration, ) { - $this->resourceConnection = $resourceConnection; - $this->indexNameResolver = $indexNameResolver; - $this->metadataPool = $metadataPool; - $this->defaultStockProvider = $defaultStockProvider; - $this->inventoryConfiguration = $inventoryConfiguration; } /** * Build bundle options stock status select * - * @param IndexName $indexName - * @param array $skuList + * @param int $stockId + * @param string[] $skuList + * @param IndexAlias $indexAlias * @return Select */ - public function execute(IndexName $indexName, array $skuList = []): Select + public function execute(int $stockId, array $skuList = [], IndexAlias $indexAlias = IndexAlias::MAIN): Select { + $indexName = $this->indexNameBuilder->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string) $stockId) + ->setAlias($indexAlias->value) + ->build(); $indexTableName = $this->indexNameResolver->resolveName($indexName); $metadata = $this->metadataPool->getMetadata(ProductInterface::class); $productLinkField = $metadata->getLinkField(); diff --git a/InventoryBundleProductIndexer/Indexer/SelectBuilder.php b/InventoryBundleProductIndexer/Indexer/SelectBuilder.php index 17914d861e4..539b4f15a00 100644 --- a/InventoryBundleProductIndexer/Indexer/SelectBuilder.php +++ b/InventoryBundleProductIndexer/Indexer/SelectBuilder.php @@ -13,7 +13,7 @@ use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\IndexStructure; use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; /** * Get bundle product for given stock select builder. @@ -53,11 +53,11 @@ public function __construct( /** * @inheritdoc */ - public function getSelect(IndexName $indexName, array $skuList = []): Select + public function getSelect(int $stockId, array $skuList = [], IndexAlias $indexAlias = IndexAlias::MAIN): Select { $connection = $this->resourceConnection->getConnection(); - $optionsStatusSelect = $this->optionsStatusSelectBuilder->execute($indexName, $skuList); + $optionsStatusSelect = $this->optionsStatusSelectBuilder->execute($stockId, $skuList, $indexAlias); $isRequiredOptionUnavailable = $connection->getCheckSql( 'options.required AND options.stock_status = 0', '1', diff --git a/InventoryBundleProductIndexer/Indexer/SiblingProductsProvider.php b/InventoryBundleProductIndexer/Indexer/SiblingProductsProvider.php index 09bca18fdbc..2c57c684be7 100644 --- a/InventoryBundleProductIndexer/Indexer/SiblingProductsProvider.php +++ b/InventoryBundleProductIndexer/Indexer/SiblingProductsProvider.php @@ -11,20 +11,16 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\EntityManager\MetadataPool; use Magento\InventoryIndexer\Indexer\SiblingProductsProviderInterface; -use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; class SiblingProductsProvider implements SiblingProductsProviderInterface { /** * @param ResourceConnection $resourceConnection * @param MetadataPool $metadataPool - * @param SiblingSelectBuilderInterface $selectBuilder */ public function __construct( private readonly ResourceConnection $resourceConnection, private readonly MetadataPool $metadataPool, - private readonly SiblingSelectBuilderInterface $selectBuilder, ) { } @@ -56,16 +52,4 @@ public function getSkus(array $skus): array return $siblingSkus; } - - /** - * @inheritdoc - */ - public function getData(IndexName $indexName, array $skuList = []): array - { - $connection = $this->resourceConnection->getConnection(); - $select = $this->selectBuilder->getSelect($indexName, $skuList); - $data = $connection->fetchAll($select); - - return $data; - } } diff --git a/InventoryBundleProductIndexer/Indexer/StockIndexer.php b/InventoryBundleProductIndexer/Indexer/StockIndexer.php deleted file mode 100644 index 543ee1274e0..00000000000 --- a/InventoryBundleProductIndexer/Indexer/StockIndexer.php +++ /dev/null @@ -1,141 +0,0 @@ -<?php -/** - * Copyright 2020 Adobe - * All Rights Reserved. - */ -declare(strict_types=1); - -namespace Magento\InventoryBundleProductIndexer\Indexer; - -use ArrayIterator; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Exception\StateException; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; -use Magento\InventoryIndexer\Indexer\InventoryIndexer; -use Magento\InventoryIndexer\Indexer\SiblingProductsProviderInterface; -use Magento\InventoryIndexer\Indexer\Stock\GetAllStockIds; -use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; - -/** - * Index bundle products for given stocks. - */ -class StockIndexer -{ - /** - * @var GetAllStockIds - */ - private $getAllStockIds; - - /** - * @var IndexStructureInterface - */ - private $indexStructure; - - /** - * @var IndexHandlerInterface - */ - private $indexHandler; - - /** - * @var IndexNameBuilder - */ - private $indexNameBuilder; - - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - - /** - * $indexStructure is reserved name for construct variable in index internal mechanism. - * - * @param GetAllStockIds $getAllStockIds - * @param IndexStructureInterface $indexStructure - * @param IndexHandlerInterface $indexHandler - * @param IndexNameBuilder $indexNameBuilder - * @param DefaultStockProviderInterface $defaultStockProvider - * @param SiblingProductsProviderInterface $productsProvider - */ - public function __construct( - GetAllStockIds $getAllStockIds, - IndexStructureInterface $indexStructure, - IndexHandlerInterface $indexHandler, - IndexNameBuilder $indexNameBuilder, - DefaultStockProviderInterface $defaultStockProvider, - private readonly SiblingProductsProviderInterface $productsProvider, - ) { - $this->getAllStockIds = $getAllStockIds; - $this->indexStructure = $indexStructure; - $this->indexHandler = $indexHandler; - $this->indexNameBuilder = $indexNameBuilder; - $this->defaultStockProvider = $defaultStockProvider; - } - - /** - * Index bundle products for all stocks. - * - * @return void - * @throws StateException - */ - public function executeFull() - { - $stockIds = $this->getAllStockIds->execute(); - $this->executeList($stockIds); - } - - /** - * Index bundle products for given stock. - * - * @param int $stockId - * @param array $skuList - * @return void - * @throws StateException - */ - public function executeRow(int $stockId, array $skuList = []) - { - $this->executeList([$stockId], $skuList); - } - - /** - * Index bundle products for given stocks. - * - * @param array $stockIds - * @param array $skuList - * @return void - * @throws StateException - */ - public function executeList(array $stockIds, array $skuList = []) - { - foreach ($stockIds as $stockId) { - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } - - $mainIndexName = $this->indexNameBuilder - ->setIndexId(InventoryIndexer::INDEXER_ID) - ->addDimension('stock_', (string)$stockId) - ->setAlias(Alias::ALIAS_MAIN) - ->build(); - - if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { - $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); - } - - $data = $this->productsProvider->getData($mainIndexName, $skuList); - $this->indexHandler->cleanIndex( - $mainIndexName, - new ArrayIterator($skuList), - ResourceConnection::DEFAULT_CONNECTION - ); - - $this->indexHandler->saveIndex( - $mainIndexName, - new ArrayIterator($data), - ResourceConnection::DEFAULT_CONNECTION - ); - } - } -} diff --git a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterAddBundleSelectionPlugin.php b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterAddBundleSelectionPlugin.php index 340acd38c30..7fb517e7a05 100644 --- a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterAddBundleSelectionPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterAddBundleSelectionPlugin.php @@ -11,7 +11,8 @@ use Magento\Bundle\Api\ProductLinkManagementInterface; use Magento\Catalog\Api\Data\ProductInterface; use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; -use Magento\InventoryBundleProductIndexer\Indexer\StockIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; use Psr\Log\LoggerInterface; /** @@ -19,34 +20,18 @@ */ class ReindexSourceItemsAfterAddBundleSelectionPlugin { - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var GetStockIdsBySkusInterface - */ - private $getStockIdsBySkus; - - /** - * @var StockIndexer - */ - private $stockIndexer; - /** * @param LoggerInterface $logger * @param GetStockIdsBySkusInterface $getStockIdsBySkus - * @param StockIndexer $stockIndexer + * @param SkuListInStockFactory $skuListInStockFactory + * @param SkuListsProcessor $skuListsProcessor */ public function __construct( - LoggerInterface $logger, - GetStockIdsBySkusInterface $getStockIdsBySkus, - StockIndexer $stockIndexer + private readonly LoggerInterface $logger, + private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, + private readonly SkuListInStockFactory $skuListInStockFactory, + private readonly SkuListsProcessor $skuListsProcessor, ) { - $this->logger = $logger; - $this->getStockIdsBySkus = $getStockIdsBySkus; - $this->stockIndexer = $stockIndexer; } /** @@ -69,7 +54,13 @@ public function afterAddChild( ): int { try { $stockIds = $this->getStockIdsBySkus->execute([$linkedProduct->getSku()]); - $this->stockIndexer->executeList($stockIds, [$product->getSku()]); + $skuListInStockList = []; + foreach ($stockIds as $stockId) { + $skuListInStockList[] = $this->skuListInStockFactory->create( + ['stockId' => $stockId, 'skuList' => [$product->getSku()]] + ); + } + $this->skuListsProcessor->reindexList($skuListInStockList); } catch (\Exception $e) { $this->logger->error($e->getMessage()); } diff --git a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterBulkAddBundleSelectionPlugin.php b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterBulkAddBundleSelectionPlugin.php index ab007a7d732..d28ccc12db7 100644 --- a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterBulkAddBundleSelectionPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterBulkAddBundleSelectionPlugin.php @@ -11,7 +11,8 @@ use Magento\Bundle\Api\ProductLinkManagementAddChildrenInterface; use Magento\Catalog\Api\Data\ProductInterface; use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; -use Magento\InventoryBundleProductIndexer\Indexer\StockIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; use Psr\Log\LoggerInterface; /** @@ -19,34 +20,18 @@ */ class ReindexSourceItemsAfterBulkAddBundleSelectionPlugin { - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var GetStockIdsBySkusInterface - */ - private $getStockIdsBySkus; - - /** - * @var StockIndexer - */ - private $stockIndexer; - /** * @param LoggerInterface $logger * @param GetStockIdsBySkusInterface $getStockIdsBySkus - * @param StockIndexer $stockIndexer + * @param SkuListInStockFactory $skuListInStockFactory + * @param SkuListsProcessor $skuListsProcessor */ public function __construct( - LoggerInterface $logger, - GetStockIdsBySkusInterface $getStockIdsBySkus, - StockIndexer $stockIndexer + private readonly LoggerInterface $logger, + private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, + private readonly SkuListInStockFactory $skuListInStockFactory, + private readonly SkuListsProcessor $skuListsProcessor, ) { - $this->logger = $logger; - $this->getStockIdsBySkus = $getStockIdsBySkus; - $this->stockIndexer = $stockIndexer; } /** @@ -70,7 +55,13 @@ public function afterAddChildren( try { $skus = array_map(fn ($linkedProduct) => $linkedProduct->getSku(), $linkedProducts); $stockIds = $this->getStockIdsBySkus->execute($skus); - $this->stockIndexer->executeList($stockIds, [$product->getSku()]); + $skuListInStockList = []; + foreach ($stockIds as $stockId) { + $skuListInStockList[] = $this->skuListInStockFactory->create( + ['stockId' => $stockId, 'skuList' => $skus] + ); + } + $this->skuListsProcessor->reindexList($skuListInStockList); } catch (\Exception $e) { $this->logger->error($e->getMessage()); } diff --git a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterRemoveBundleSelectionPlugin.php b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterRemoveBundleSelectionPlugin.php index 8ca9b7db77c..43eb3685f61 100644 --- a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterRemoveBundleSelectionPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterRemoveBundleSelectionPlugin.php @@ -9,7 +9,8 @@ use Magento\Bundle\Api\ProductLinkManagementInterface; use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; -use Magento\InventoryBundleProductIndexer\Indexer\StockIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; use Psr\Log\LoggerInterface; /** @@ -17,34 +18,18 @@ */ class ReindexSourceItemsAfterRemoveBundleSelectionPlugin { - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var GetStockIdsBySkusInterface - */ - private $getStockIdsBySkus; - - /** - * @var StockIndexer - */ - private $stockIndexer; - /** * @param LoggerInterface $logger * @param GetStockIdsBySkusInterface $getStockIdsBySkus - * @param StockIndexer $stockIndexer + * @param SkuListInStockFactory $skuListInStockFactory + * @param SkuListsProcessor $skuListsProcessor */ public function __construct( - LoggerInterface $logger, - GetStockIdsBySkusInterface $getStockIdsBySkus, - StockIndexer $stockIndexer + private readonly LoggerInterface $logger, + private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, + private readonly SkuListInStockFactory $skuListInStockFactory, + private readonly SkuListsProcessor $skuListsProcessor, ) { - $this->logger = $logger; - $this->getStockIdsBySkus = $getStockIdsBySkus; - $this->stockIndexer = $stockIndexer; } /** @@ -67,7 +52,13 @@ public function afterRemoveChild( ): bool { try { $stockIds = $this->getStockIdsBySkus->execute([$childSku]); - $this->stockIndexer->executeList($stockIds, [$sku]); + $skuListInStockList = []; + foreach ($stockIds as $stockId) { + $skuListInStockList[] = $this->skuListInStockFactory->create( + ['stockId' => $stockId, 'skuList' => [$sku]] + ); + } + $this->skuListsProcessor->reindexList($skuListInStockList); } catch (\Exception $e) { $this->logger->error($e->getMessage()); } diff --git a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterSaveBundleSelectionPlugin.php b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterSaveBundleSelectionPlugin.php index 01cee05380a..aa6ec38a11e 100644 --- a/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterSaveBundleSelectionPlugin.php +++ b/InventoryBundleProductIndexer/Plugin/Bundle/Model/LinkManagement/ReindexSourceItemsAfterSaveBundleSelectionPlugin.php @@ -10,7 +10,8 @@ use Magento\Bundle\Api\Data\LinkInterface; use Magento\Bundle\Api\ProductLinkManagementInterface; use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; -use Magento\InventoryBundleProductIndexer\Indexer\StockIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; use Psr\Log\LoggerInterface; /** @@ -18,34 +19,18 @@ */ class ReindexSourceItemsAfterSaveBundleSelectionPlugin { - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var GetStockIdsBySkusInterface - */ - private $getStockIdsBySkus; - - /** - * @var StockIndexer - */ - private $stockIndexer; - /** * @param LoggerInterface $logger * @param GetStockIdsBySkusInterface $getStockIdsBySkus - * @param StockIndexer $stockIndexer + * @param SkuListInStockFactory $skuListInStockFactory + * @param SkuListsProcessor $skuListsProcessor */ public function __construct( - LoggerInterface $logger, - GetStockIdsBySkusInterface $getStockIdsBySkus, - StockIndexer $stockIndexer + private readonly LoggerInterface $logger, + private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, + private readonly SkuListInStockFactory $skuListInStockFactory, + private readonly SkuListsProcessor $skuListsProcessor, ) { - $this->logger = $logger; - $this->getStockIdsBySkus = $getStockIdsBySkus; - $this->stockIndexer = $stockIndexer; } /** @@ -66,7 +51,13 @@ public function afterSaveChild( ): bool { try { $stockIds = $this->getStockIdsBySkus->execute([$linkedProduct->getSku()]); - $this->stockIndexer->executeList($stockIds, [$sku]); + $skuListInStockList = []; + foreach ($stockIds as $stockId) { + $skuListInStockList[] = $this->skuListInStockFactory->create( + ['stockId' => $stockId, 'skuList' => [$sku]] + ); + } + $this->skuListsProcessor->reindexList($skuListInStockList); } catch (\Exception $e) { $this->logger->error($e->getMessage()); } diff --git a/InventoryBundleProductIndexer/Test/Integration/Indexer/StockIndexerTest.php b/InventoryBundleProductIndexer/Test/Integration/Indexer/StockIndexerTest.php index 3ee40c9d1e4..e89d8ae9344 100644 --- a/InventoryBundleProductIndexer/Test/Integration/Indexer/StockIndexerTest.php +++ b/InventoryBundleProductIndexer/Test/Integration/Indexer/StockIndexerTest.php @@ -18,7 +18,8 @@ use Magento\InventoryApi\Test\Fixture\SourceItems as SourceItemsFixture; use Magento\InventoryApi\Test\Fixture\Stock as StockFixture; use Magento\InventoryApi\Test\Fixture\StockSourceLinks as StockSourceLinksFixture; -use Magento\InventoryBundleProductIndexer\Indexer\StockIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; use Magento\InventoryIndexer\Model\ResourceModel\GetStockItemData; use Magento\InventorySalesApi\Model\GetStockItemDataInterface; use Magento\InventorySalesApi\Test\Fixture\StockSalesChannels as StockSalesChannelsFixture; @@ -37,9 +38,14 @@ class StockIndexerTest extends TestCase private $fixtures; /** - * @var StockIndexer + * @var SkuListsProcessor */ - private $stockIndexer; + private $skuListsProcessor; + + /** + * @var SkuListInStockFactory + */ + private $skuListInStockFactory; /** * @var GetSourceItemsBySkuInterface @@ -59,7 +65,8 @@ class StockIndexerTest extends TestCase protected function setUp(): void { $this->fixtures = DataFixtureStorageManager::getStorage(); - $this->stockIndexer = Bootstrap::getObjectManager()->create(StockIndexer::class); + $this->skuListsProcessor = Bootstrap::getObjectManager()->create(SkuListsProcessor::class); + $this->skuListInStockFactory = Bootstrap::getObjectManager()->get(SkuListInStockFactory::class); $this->getSourceItemsBySku = Bootstrap::getObjectManager()->get(GetSourceItemsBySkuInterface::class); $this->sourceItemsSave = Bootstrap::getObjectManager()->get(SourceItemsSaveInterface::class); $this->getStockItemData = Bootstrap::getObjectManager()->get(GetStockItemData::class); @@ -148,7 +155,11 @@ public function testExecuteList(array $newSourceData, bool $expectedStockStatus) $this->sourceItemsSave->execute($sourceItems); } - $this->stockIndexer->executeList([$stock->getStockId()], ['bundle1']); + $skuListInStock = $this->skuListInStockFactory->create( + ['stockId' => $stock->getStockId(), 'skuList' => ['bundle1']] + ); + $this->skuListsProcessor->reindexList([$skuListInStock]); + $bundleStockItem = $this->getStockItemData->execute('bundle1', $stock->getStockId()); self::assertEquals($expectedStockStatus, (bool) $bundleStockItem[GetStockItemDataInterface::IS_SALABLE]); } diff --git a/InventoryBundleProductIndexer/etc/di.xml b/InventoryBundleProductIndexer/etc/di.xml index 148d9862cfe..c7b42faaeca 100644 --- a/InventoryBundleProductIndexer/etc/di.xml +++ b/InventoryBundleProductIndexer/etc/di.xml @@ -6,11 +6,6 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <type name="Magento\InventoryBundleProductIndexer\Indexer\StockIndexer"> - <arguments> - <argument name="productsProvider" xsi:type="object">Magento\InventoryBundleProductIndexer\Indexer\SiblingProductsProvider</argument> - </arguments> - </type> <type name="Magento\Bundle\Api\ProductLinkManagementInterface"> <plugin name="reindex_source_items_after_add_bundle_selection" type="Magento\InventoryBundleProductIndexer\Plugin\Bundle\Model\LinkManagement\ReindexSourceItemsAfterAddBundleSelectionPlugin"/> <plugin name="reindex_source_items_after_save_bundle_selection" type="Magento\InventoryBundleProductIndexer\Plugin\Bundle\Model\LinkManagement\ReindexSourceItemsAfterSaveBundleSelectionPlugin"/> @@ -19,12 +14,14 @@ <type name="Magento\Bundle\Api\ProductLinkManagementAddChildrenInterface"> <plugin name="reindex_source_items_after_bulk_add_bundle_selection" type="Magento\InventoryBundleProductIndexer\Plugin\Bundle\Model\LinkManagement\ReindexSourceItemsAfterBulkAddBundleSelectionPlugin"/> </type> - <type name="Magento\InventoryBundleProductIndexer\Indexer\SiblingProductsProvider"> + <type name="Magento\InventoryIndexer\Indexer\Stock\DataProvider"> <arguments> - <argument name="selectBuilder" xsi:type="object">Magento\InventoryBundleProductIndexer\Indexer\SelectBuilder</argument> + <argument name="siblingSelectBuilders" xsi:type="array"> + <item name="bundle" xsi:type="object">Magento\InventoryBundleProductIndexer\Indexer\SelectBuilder</item> + </argument> </arguments> </type> - <type name="Magento\InventoryIndexer\Indexer\Stock\IndexDataFiller"> + <type name="Magento\InventoryIndexer\Indexer\SiblingProductsProvidersPool"> <arguments> <argument name="siblingProductsProviders" xsi:type="array"> <item name="bundle" xsi:type="object">Magento\InventoryBundleProductIndexer\Indexer\SiblingProductsProvider</item> diff --git a/InventoryCatalog/Model/GetChildrenSkusOfParentSkus.php b/InventoryCatalog/Model/GetChildrenSkusOfParentSkus.php new file mode 100644 index 00000000000..87228993aa2 --- /dev/null +++ b/InventoryCatalog/Model/GetChildrenSkusOfParentSkus.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryCatalog\Model; + +use Magento\Catalog\Model\ResourceModel\Product\Relation; +use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface; +use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use Magento\InventoryCatalogApi\Model\GetChildrenSkusOfParentSkusInterface; + +/** + * @inheritdoc + */ +class GetChildrenSkusOfParentSkus implements GetChildrenSkusOfParentSkusInterface +{ + /** + * @param Relation $productRelationResource + * @param GetProductIdsBySkusInterface $getProductIdsBySkus + * @param GetSkusByProductIdsInterface $getSkusByProductIds + */ + public function __construct( + private readonly Relation $productRelationResource, + private readonly GetProductIdsBySkusInterface $getProductIdsBySkus, + private readonly GetSkusByProductIdsInterface $getSkusByProductIds + ) { + } + + /** + * @inheritdoc + */ + public function execute(array $skus): array + { + if (!$skus) { + return []; + } + + $parentIds = $this->getProductIdsBySkus->execute($skus); + $childIdsOfParentIds = $this->productRelationResource->getRelationsByParent(array_values($parentIds)); + $flatChildIds = array_merge([], ...$childIdsOfParentIds); + $childSkus = $flatChildIds ? $this->getSkusByProductIds->execute(array_unique($flatChildIds)) : []; + + $childSkusOfParentSkus = []; + foreach ($skus as $sku) { + $parentId = $parentIds[$sku]; + $childSkusOfParentSkus[$sku] = array_map( + fn ($childId) => $childSkus[$childId], + $childIdsOfParentIds[$parentId] ?? [] + ); + } + + return $childSkusOfParentSkus; + } +} diff --git a/InventoryCatalog/Test/Unit/Model/GetChildrenSkusOfParentSkusTest.php b/InventoryCatalog/Test/Unit/Model/GetChildrenSkusOfParentSkusTest.php new file mode 100644 index 00000000000..eedfff6ccc7 --- /dev/null +++ b/InventoryCatalog/Test/Unit/Model/GetChildrenSkusOfParentSkusTest.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryCatalog\Test\Unit\Model; + +use Magento\Catalog\Model\ResourceModel\Product\Relation; +use Magento\InventoryCatalog\Model\GetChildrenSkusOfParentSkus; +use Magento\InventoryCatalogApi\Model\GetProductIdsBySkusInterface; +use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class GetChildrenSkusOfParentSkusTest extends TestCase +{ + /** + * @var Relation|MockObject + */ + private $productRelationResourceMock; + + /** + * @var GetProductIdsBySkusInterface|MockObject + */ + private $getProductIdsBySkusMock; + + /** + * @var GetSkusByProductIdsInterface|MockObject + */ + private $getSkusByProductIdsMock; + + /** + * @var GetChildrenSkusOfParentSkus + */ + private $model; + + protected function setUp(): void + { + $this->productRelationResourceMock = $this->createMock(Relation::class); + $this->getProductIdsBySkusMock = $this->createMock(GetProductIdsBySkusInterface::class); + $this->getSkusByProductIdsMock = $this->createMock(GetSkusByProductIdsInterface::class); + $this->model = new GetChildrenSkusOfParentSkus( + $this->productRelationResourceMock, + $this->getProductIdsBySkusMock, + $this->getSkusByProductIdsMock, + ); + } + + public function testExecuteNoSkus(): void + { + $this->getProductIdsBySkusMock->expects(self::never())->method('execute'); + $this->productRelationResourceMock->expects(self::never())->method('getRelationsByParent'); + $this->model->execute([]); + } + + public function testExecute(): void + { + $childrenSkusOfParentSkus = [ + 'configurable1' => ['simple-1'], + 'grouped1' => [], + 'bundle1' => ['simple-1', 'simple-2'], + ]; + + $this->getProductIdsBySkusMock->expects(self::once())->method('execute') + ->with(array_keys($childrenSkusOfParentSkus)) + ->willReturn(['configurable1' => 10, 'grouped1' => 20, 'bundle1' => 30]); + $this->productRelationResourceMock->expects(self::once())->method('getRelationsByParent') + ->with([10, 20, 30]) + ->willReturn([10 => [2], 20 => [], 30 => [2, 3]]); + $this->getSkusByProductIdsMock->expects(self::once())->method('execute') + ->with(self::equalToCanonicalizing([2, 3])) + ->willReturn([2 => 'simple-1', 3 => 'simple-2']); + + $result = $this->model->execute(array_keys($childrenSkusOfParentSkus)); + self::assertEquals($childrenSkusOfParentSkus, $result); + } +} diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 1804eefed78..4ef4b84f88d 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -12,6 +12,7 @@ <preference for="Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface" type="Magento\InventoryCatalog\Model\ResourceModel\GetProductTypesBySkusCache" /> <preference for="Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface" type="Magento\InventoryCatalog\Model\GetSkusByProductIdsCache"/> <preference for="Magento\InventoryCatalogApi\Model\GetParentSkusOfChildrenSkusInterface" type="Magento\InventoryCatalog\Model\GetParentSkusOfChildrenSkus"/> + <preference for="Magento\InventoryCatalogApi\Model\GetChildrenSkusOfParentSkusInterface" type="Magento\InventoryCatalog\Model\GetChildrenSkusOfParentSkus"/> <preference for="Magento\InventoryCatalogApi\Model\IsSingleSourceModeInterface" type="Magento\InventoryCatalog\Model\IsSingleSourceModeCache"/> <preference for="Magento\InventoryCatalogApi\Model\SourceItemsProcessorInterface" type="Magento\InventoryCatalog\Model\SourceItemsProcessor"/> <preference for="Magento\CatalogInventory\Model\StockStatusApplierInterface" type="Magento\InventoryCatalog\Model\StockStatusApplier" /> diff --git a/InventoryCatalogApi/Model/GetChildrenSkusOfParentSkusInterface.php b/InventoryCatalogApi/Model/GetChildrenSkusOfParentSkusInterface.php new file mode 100644 index 00000000000..cba302bd587 --- /dev/null +++ b/InventoryCatalogApi/Model/GetChildrenSkusOfParentSkusInterface.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryCatalogApi\Model; + +/** + * Provides relational children product SKUs by given parent SKUs + */ +interface GetChildrenSkusOfParentSkusInterface +{ + /** + * Returns children SKUs of parent SKUs. + * + * Resulting array is like: + * ```php + * [ + * 'bundle1' => [], + * 'configurable1' => ['configurable1-red', 'configurable1-green'], + * 'grouped1' => ['simple1'], + * ] + * ``` + * + * @param string[] $skus Parents SKUs + * @return array<string, string[]> Array of children SKUs arrays that belong to parents SKUs + */ + public function execute(array $skus): array; +} diff --git a/InventoryConfigurableProductIndexer/Indexer/SelectBuilder.php b/InventoryConfigurableProductIndexer/Indexer/SelectBuilder.php index b7781a779ed..bfff352d036 100644 --- a/InventoryConfigurableProductIndexer/Indexer/SelectBuilder.php +++ b/InventoryConfigurableProductIndexer/Indexer/SelectBuilder.php @@ -13,55 +13,40 @@ use Magento\Framework\EntityManager\MetadataPool; use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\IndexStructure; +use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameResolverInterface; class SelectBuilder implements SiblingSelectBuilderInterface { - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var IndexNameResolverInterface - */ - private $indexNameResolver; - - /** - * @var MetadataPool - */ - private $metadataPool; - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - /** * @param ResourceConnection $resourceConnection + * @param IndexNameBuilder $indexNameBuilder * @param IndexNameResolverInterface $indexNameResolver * @param MetadataPool $metadataPool * @param DefaultStockProviderInterface $defaultStockProvider */ public function __construct( - ResourceConnection $resourceConnection, - IndexNameResolverInterface $indexNameResolver, - MetadataPool $metadataPool, - DefaultStockProviderInterface $defaultStockProvider + private readonly ResourceConnection $resourceConnection, + private readonly IndexNameBuilder $indexNameBuilder, + private readonly IndexNameResolverInterface $indexNameResolver, + private readonly MetadataPool $metadataPool, + private readonly DefaultStockProviderInterface $defaultStockProvider ) { - $this->resourceConnection = $resourceConnection; - $this->indexNameResolver = $indexNameResolver; - $this->metadataPool = $metadataPool; - $this->defaultStockProvider = $defaultStockProvider; } /** * @inheritdoc */ - public function getSelect(IndexName $indexName, array $skuList = []): Select + public function getSelect(int $stockId, array $skuList = [], IndexAlias $indexAlias = IndexAlias::MAIN): Select { $connection = $this->resourceConnection->getConnection(); + $indexName = $this->indexNameBuilder->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string) $stockId) + ->setAlias($indexAlias->value) + ->build(); $indexTableName = $this->indexNameResolver->resolveName($indexName); $metadata = $this->metadataPool->getMetadata(ProductInterface::class); $linkField = $metadata->getLinkField(); diff --git a/InventoryConfigurableProductIndexer/Indexer/SiblingProductsProvider.php b/InventoryConfigurableProductIndexer/Indexer/SiblingProductsProvider.php index b629245764f..0567b983ccc 100644 --- a/InventoryConfigurableProductIndexer/Indexer/SiblingProductsProvider.php +++ b/InventoryConfigurableProductIndexer/Indexer/SiblingProductsProvider.php @@ -11,20 +11,16 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\EntityManager\MetadataPool; use Magento\InventoryIndexer\Indexer\SiblingProductsProviderInterface; -use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; class SiblingProductsProvider implements SiblingProductsProviderInterface { /** * @param ResourceConnection $resourceConnection * @param MetadataPool $metadataPool - * @param SiblingSelectBuilderInterface $selectBuilder */ public function __construct( private readonly ResourceConnection $resourceConnection, private readonly MetadataPool $metadataPool, - private readonly SiblingSelectBuilderInterface $selectBuilder, ) { } @@ -56,16 +52,4 @@ public function getSkus(array $skus): array return $siblingSkus; } - - /** - * @inheritdoc - */ - public function getData(IndexName $indexName, array $skuList = []): array - { - $connection = $this->resourceConnection->getConnection(); - $select = $this->selectBuilder->getSelect($indexName, $skuList); - $data = $connection->fetchAll($select); - - return $data; - } } diff --git a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SiblingSkuListInStockProvider.php b/InventoryConfigurableProductIndexer/Indexer/SourceItem/SiblingSkuListInStockProvider.php deleted file mode 100644 index e21f0c841b1..00000000000 --- a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SiblingSkuListInStockProvider.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php -/** - * Copyright 2018 Adobe - * All Rights Reserved. - */ -declare(strict_types=1); - -namespace Magento\InventoryConfigurableProductIndexer\Indexer\SourceItem; - -use Exception; -use Magento\Framework\App\ResourceConnection; -use Magento\InventoryApi\Api\Data\SourceItemInterface; -use Magento\InventoryApi\Api\Data\StockSourceLinkInterface; -use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStock; -use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; -use Magento\Framework\EntityManager\MetadataPool; -use Magento\Catalog\Api\Data\ProductInterface; - -/** - * Returns relations between stock and sku list - */ -class SiblingSkuListInStockProvider -{ - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var SkuListInStockFactory - */ - private $skuListInStockFactory; - - /** - * @var MetadataPool - */ - private $metadataPool; - - /** - * @var string - */ - private $tableNameSourceItem; - - /** - * @var string - */ - private $tableNameStockSourceLink; - - /** - * GetSkuListInStock constructor. - * - * @param ResourceConnection $resourceConnection - * @param SkuListInStockFactory $skuListInStockFactory - * @param MetadataPool $metadataPool - * @param string $tableNameSourceItem - * @param string $tableNameStockSourceLink - */ - public function __construct( - ResourceConnection $resourceConnection, - SkuListInStockFactory $skuListInStockFactory, - MetadataPool $metadataPool, - $tableNameSourceItem, - $tableNameStockSourceLink - ) { - $this->resourceConnection = $resourceConnection; - $this->skuListInStockFactory = $skuListInStockFactory; - $this->metadataPool = $metadataPool; - $this->tableNameSourceItem = $tableNameSourceItem; - $this->tableNameStockSourceLink = $tableNameStockSourceLink; - } - - /** - * Returns all assigned Stock ids by given Source Item ids - * - * @param int[] $sourceItemIds - * @return SkuListInStock[] List of stock id to sku1,sku2 assignment - * @throws Exception - */ - public function execute(array $sourceItemIds): array - { - $connection = $this->resourceConnection->getConnection(); - $sourceStockLinkTable = $this->resourceConnection->getTableName($this->tableNameStockSourceLink); - $sourceItemTable = $this->resourceConnection->getTableName($this->tableNameSourceItem); - - $metadata = $this->metadataPool->getMetadata(ProductInterface::class); - $items = []; - - $select = $connection - ->select() - ->from( - ['source_item' => $sourceItemTable], - [] - )->joinInner( - ['stock_source_link' => $sourceStockLinkTable], - sprintf( - 'source_item.%s = stock_source_link.%s', - SourceItemInterface::SOURCE_CODE, - StockSourceLinkInterface::SOURCE_CODE - ), - [StockSourceLinkInterface::STOCK_ID] - )->joinInner( - ['child_product_entity' => $this->resourceConnection->getTableName('catalog_product_entity')], - 'child_product_entity.sku = source_item.sku', - [] - )->joinInner( - ['parent_link' => $this->resourceConnection->getTableName('catalog_product_super_link')], - 'parent_link.product_id = child_product_entity.' . $metadata->getIdentifierField(), - [] - )->joinInner( - ['sibling_product_entity' => $this->resourceConnection->getTableName('catalog_product_entity')], - 'sibling_product_entity.' . $metadata->getLinkField() . ' = parent_link.parent_id', - ['sku' => 'sibling_product_entity.sku'] - )->where( - 'source_item.source_item_id IN (?)', - $sourceItemIds - )->group( - ['stock_source_link.' . StockSourceLinkInterface::STOCK_ID, 'sibling_product_entity.sku'] - ); - - $dbStatement = $connection->query($select); - while ($item = $dbStatement->fetch()) { - $items[$item[StockSourceLinkInterface::STOCK_ID]][$item[SourceItemInterface::SKU]] = - $item[SourceItemInterface::SKU]; - } - - return $this->getStockIdToSkuList($items); - } - - /** - * Return the assigned stock id to sku list - * - * @param array $items - * @return SkuListInStock[] - */ - private function getStockIdToSkuList(array $items): array - { - $skuListInStockList = []; - foreach ($items as $stockId => $skuList) { - /** @var SkuListInStock $skuListInStock */ - $skuListInStock = $this->skuListInStockFactory->create(); - $skuListInStock->setStockId((int)$stockId); - $skuListInStock->setSkuList($skuList); - $skuListInStockList[] = $skuListInStock; - } - return $skuListInStockList; - } -} diff --git a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php b/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php deleted file mode 100644 index c7b3da034ca..00000000000 --- a/InventoryConfigurableProductIndexer/Indexer/SourceItem/SourceItemIndexer.php +++ /dev/null @@ -1,160 +0,0 @@ -<?php -/** - * Copyright 2018 Adobe - * All Rights Reserved. - */ -declare(strict_types=1); - -namespace Magento\InventoryConfigurableProductIndexer\Indexer\SourceItem; - -use Magento\Framework\App\DeploymentConfig; -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Indexer\SaveHandler\Batch; -use Magento\InventoryIndexer\Indexer\SiblingProductsProviderInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; -use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; -use Magento\InventoryIndexer\Indexer\InventoryIndexer; -use ArrayIterator; - -/** - * Configurable product source item indexer - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) Will be removed after deleting DefaultStockProviderInterface - */ -class SourceItemIndexer -{ - /** - * @var IndexNameBuilder - */ - private $indexNameBuilder; - - /** - * @var IndexHandlerInterface - */ - private $indexHandler; - - /** - * @var IndexStructureInterface - */ - private $indexStructure; - - /** - * @var SiblingSkuListInStockProvider - */ - private $siblingSkuListInStockProvider; - - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - - /** - * @var int - */ - private $batchSize; - - /** - * @var Batch - */ - private $batch; - - /** - * @var DeploymentConfig - */ - private $deploymentConfig; - - /** - * Deployment config path - * - * @var string - */ - private const DEPLOYMENT_CONFIG_INDEXER_BATCHES = 'indexer/batch_size/'; - - /** - * @param IndexNameBuilder $indexNameBuilder - * @param IndexHandlerInterface $indexHandler - * @param IndexStructureInterface $indexStructure - * @param SiblingSkuListInStockProvider $siblingSkuListInStockProvider - * @param DefaultStockProviderInterface $defaultStockProvider - * @param Batch $batch - * @param DeploymentConfig $deploymentConfig - * @param SiblingProductsProviderInterface $productsProvider - * @param int $batchSize - */ - public function __construct( - IndexNameBuilder $indexNameBuilder, - IndexHandlerInterface $indexHandler, - IndexStructureInterface $indexStructure, - SiblingSkuListInStockProvider $siblingSkuListInStockProvider, - DefaultStockProviderInterface $defaultStockProvider, - Batch $batch, - DeploymentConfig $deploymentConfig, - private readonly SiblingProductsProviderInterface $productsProvider, - int $batchSize = 100, - ) { - $this->indexNameBuilder = $indexNameBuilder; - $this->indexHandler = $indexHandler; - $this->indexStructure = $indexStructure; - $this->siblingSkuListInStockProvider = $siblingSkuListInStockProvider; - $this->defaultStockProvider = $defaultStockProvider; - $this->batch = $batch; - $this->deploymentConfig = $deploymentConfig; - $this->batchSize = $batchSize; - } - - /** - * Executes index by list of stock ids - * - * @param array $sourceItemIds - */ - public function executeList(array $sourceItemIds) - { - $skuListInStockList = $this->siblingSkuListInStockProvider->execute($sourceItemIds); - $this->batchSize = $this->deploymentConfig->get( - self::DEPLOYMENT_CONFIG_INDEXER_BATCHES . InventoryIndexer::INDEXER_ID . '/' . 'configurable' - ) ?? - $this->deploymentConfig->get( - self::DEPLOYMENT_CONFIG_INDEXER_BATCHES . InventoryIndexer::INDEXER_ID . '/' . 'default' - ) - ?? $this->batchSize; - - foreach ($skuListInStockList as $skuListInStock) { - $stockId = $skuListInStock->getStockId(); - - if ($this->defaultStockProvider->getId() === $stockId) { - continue; - } - $skuList = $skuListInStock->getSkuList(); - - $mainIndexName = $this->indexNameBuilder - ->setIndexId(InventoryIndexer::INDEXER_ID) - ->addDimension('stock_', (string)$stockId) - ->setAlias(Alias::ALIAS_MAIN) - ->build(); - - if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { - $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); - } - - $data = $this->productsProvider->getData($mainIndexName, $skuList); - $indexData = new ArrayIterator($data); - foreach ($this->batch->getItems($indexData, $this->batchSize) as $batchData) { - $batchIndexData = new ArrayIterator($batchData); - $this->indexHandler->cleanIndex( - $mainIndexName, - $batchIndexData, - ResourceConnection::DEFAULT_CONNECTION - ); - - $this->indexHandler->saveIndex( - $mainIndexName, - $batchIndexData, - ResourceConnection::DEFAULT_CONNECTION - ); - } - } - } -} diff --git a/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php index dced0d60b0a..6969a0c2a6b 100644 --- a/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php +++ b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php @@ -11,78 +11,25 @@ use Magento\ConfigurableProduct\Model\Product\Type\Configurable; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Model\AbstractModel; -use Magento\InventoryApi\Api\GetSourceItemsBySkuInterface; -use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface; +use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; -use Magento\InventoryConfigurableProductIndexer\Indexer\SourceItem\SourceItemIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; class APISourceItemIndexerPlugin { /** - * @var SourceItemIndexer - */ - private SourceItemIndexer $configurableProductsSourceItemIndexer; - - /** - * @var GetSourceItemsBySkuInterface - */ - private GetSourceItemsBySkuInterface $getSourceItemsBySku; - - /** - * @var DefaultSourceProviderInterface - */ - private DefaultSourceProviderInterface $defaultSourceProvider; - - /** - * @var GetSkusByProductIdsInterface - */ - private GetSkusByProductIdsInterface $skuProvider; - - /** - * @param SourceItemIndexer $configurableProductsSourceItemIndexer - * @param GetSourceItemsBySkuInterface $getSourceItemsBySku - * @param DefaultSourceProviderInterface $defaultSourceProvider - * @param GetSkusByProductIdsInterface $getSkusByProductIdsInterface + * @param GetSkusByProductIdsInterface $getSkusByProductIds + * @param GetStockIdsBySkusInterface $getStockIdsBySkus + * @param SkuListInStockFactory $skuListInStockFactory + * @param SkuListsProcessor $skuListsProcessor */ public function __construct( - SourceItemIndexer $configurableProductsSourceItemIndexer, - GetSourceItemsBySkuInterface $getSourceItemsBySku, - DefaultSourceProviderInterface $defaultSourceProvider, - GetSkusByProductIdsInterface $getSkusByProductIdsInterface + private readonly GetSkusByProductIdsInterface $getSkusByProductIds, + private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, + private readonly SkuListInStockFactory $skuListInStockFactory, + private readonly SkuListsProcessor $skuListsProcessor, ) { - $this->configurableProductsSourceItemIndexer = $configurableProductsSourceItemIndexer; - $this->getSourceItemsBySku = $getSourceItemsBySku; - $this->defaultSourceProvider = $defaultSourceProvider; - $this->skuProvider = $getSkusByProductIdsInterface; - } - - /** - * Extracts product source item ids - * - * @param array $childProductIds - * @return array - * @throws NoSuchEntityException - */ - private function getProductSourceItemIds(array $childProductIds): array - { - $sourceItemIds = []; - foreach ($childProductIds as $productIds) { - if (empty($productIds)) { - continue; - } - foreach ($this->skuProvider->execute($productIds) as $childSku) { - $sourceItems = $this->getSourceItemsBySku->execute($childSku); - foreach ($sourceItems as $key => $sourceItem) { - if ($sourceItem->getSourceCode() === $this->defaultSourceProvider->getCode()) { - unset($sourceItems[$key]); - continue; - } - $sourceItemIds[] = $sourceItem->getId(); - } - } - } - - return $sourceItemIds; } /** @@ -105,9 +52,18 @@ public function afterSave( } $childProductIds = $product->getTypeInstance()->getChildrenIds($product->getId()); - $sourceItemIds = $this->getProductSourceItemIds($childProductIds); - if ($sourceItemIds) { - $this->configurableProductsSourceItemIndexer->executeList($sourceItemIds); + $childProductSkus = $this->getSkusByProductIds->execute($childProductIds[0]); + $stockIds = $this->getStockIdsBySkus->execute($childProductSkus); + if ($stockIds) { + $skuListInStockList = []; + foreach ($stockIds as $stockId) { + $skuListInStock = $this->skuListInStockFactory->create( + ['stockId' => $stockId, 'skuList' => [$product->getSku()]] + ); + $skuListInStockList[] = $skuListInStock; + } + $this->skuListsProcessor->reindexList($skuListInStockList); + $product->setIsChangedCategories(true); $product->setAffectedCategoryIds($product->getCategoryIds()); $product->cleanModelCache(); diff --git a/InventoryConfigurableProductIndexer/Test/Integration/Indexer/SiblingProductsProviderTest.php b/InventoryConfigurableProductIndexer/Test/Integration/Indexer/SelectBuilderTest.php similarity index 54% rename from InventoryConfigurableProductIndexer/Test/Integration/Indexer/SiblingProductsProviderTest.php rename to InventoryConfigurableProductIndexer/Test/Integration/Indexer/SelectBuilderTest.php index 8ebce29c64a..a88f01b255a 100644 --- a/InventoryConfigurableProductIndexer/Test/Integration/Indexer/SiblingProductsProviderTest.php +++ b/InventoryConfigurableProductIndexer/Test/Integration/Indexer/SelectBuilderTest.php @@ -7,25 +7,28 @@ namespace Magento\InventoryConfigurableProductIndexer\Test\Integration\Indexer; -use Magento\InventoryConfigurableProductIndexer\Indexer\SiblingProductsProvider; -use Magento\InventoryIndexer\Indexer\InventoryIndexer; -use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; +use Magento\ConfigurableProduct\Model\Product\Type\Configurable as ConfigurableType; +use Magento\InventoryConfigurableProductIndexer\Indexer\SelectBuilder; +use Magento\InventoryIndexer\Indexer\Stock\DataProvider; use Magento\TestFramework\Fixture\DataFixture; use Magento\TestFramework\Fixture\DbIsolation; use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -class SiblingProductsProviderTest extends TestCase +#[ + CoversClass(SelectBuilder::class), +] +class SelectBuilderTest extends TestCase { /** - * @var SiblingProductsProvider + * @var DataProvider */ - private $siblingProductsProvider; + private $dataProvider; protected function setUp(): void { - $this->siblingProductsProvider = Bootstrap::getObjectManager()->create(SiblingProductsProvider::class); + $this->dataProvider = Bootstrap::getObjectManager()->create(DataProvider::class); } #[ @@ -42,17 +45,12 @@ protected function setUp(): void public function testGetSelect(): void { $stockId = 10; - $skus = []; - - $indexNameBuilder = Bootstrap::getObjectManager()->get(IndexNameBuilder::class); - $indexName = $indexNameBuilder->setIndexId(InventoryIndexer::INDEXER_ID) - ->addDimension('stock_', (string) $stockId) - ->setAlias(Alias::ALIAS_MAIN) - ->build(); - $indexData = $this->siblingProductsProvider->getData($indexName); - foreach ($indexData as $item) { - $skus[] = $item['sku']; - } - $this->assertContains('configurable_1', $skus); + $sku = 'configurable_1'; + $indexData = $this->dataProvider->getSiblingsData($stockId, ConfigurableType::TYPE_CODE, [$sku]); + self::assertCount(1, $indexData); + $row = reset($indexData); + self::assertEquals($sku, $row['sku']); + self::assertEquals(300, $row['quantity']); + self::assertEquals(1, $row['is_salable']); } } diff --git a/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php b/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php index 556e04680be..5e395fa53ca 100644 --- a/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php +++ b/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php @@ -12,65 +12,67 @@ use Magento\Catalog\Model\Product\Type\AbstractType; use Magento\Catalog\Model\ResourceModel\Product as ProductResource; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; -use Magento\Inventory\Model\SourceItem; -use Magento\InventoryApi\Api\GetSourceItemsBySkuInterface; -use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface; +use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface; -use Magento\InventoryConfigurableProductIndexer\Indexer\SourceItem\SourceItemIndexer; use Magento\InventoryConfigurableProductIndexer\Plugin\InventoryIndexer\Indexer\SourceItem\Strategy\Sync\APISourceItemIndexerPlugin; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStock; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; // @codingStandardsIgnoreEnd -/** - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ class APISourceItemIndexerPluginTest extends TestCase { /** - * @var SourceItemIndexer|MockObject + * @var APISourceItemIndexerPlugin */ - private SourceItemIndexer $configurableProductsSourceItemIndexer; + private $plugin; /** - * @var GetSourceItemsBySkuInterface|MockObject + * @var GetSkusByProductIdsInterface|MockObject */ - private GetSourceItemsBySkuInterface $getSourceItemsBySku; + private $getSkusByProductIdsMock; /** - * @var DefaultSourceProviderInterface|MockObject + * @var GetStockIdsBySkusInterface|MockObject */ - private DefaultSourceProviderInterface $defaultSourceProvider; + private $getStockIdsBySkusMock; /** - * @var GetSkusByProductIdsInterface|MockObject + * @var SkuListInStockFactory|MockObject */ - private GetSkusByProductIdsInterface $skuProvider; + private $skuListInStockFactoryMock; /** - * @var APISourceItemIndexerPlugin|MockObject + * @var SkuListsProcessor|MockObject */ - private APISourceItemIndexerPlugin $plugin; + private $skuListsProcessorMock; protected function setUp(): void { - $this->configurableProductsSourceItemIndexer = $this->createMock(SourceItemIndexer::class); - $this->getSourceItemsBySku = $this->createMock(GetSourceItemsBySkuInterface::class); - $this->defaultSourceProvider = $this->createMock(DefaultSourceProviderInterface::class); - $this->skuProvider = $this->createMock(GetSkusByProductIdsInterface::class); + parent::setUp(); + $this->getSkusByProductIdsMock = $this->createMock(GetSkusByProductIdsInterface::class); + $this->getStockIdsBySkusMock = $this->createMock(GetStockIdsBySkusInterface::class); + $this->skuListInStockFactoryMock = $this->createMock(SkuListInStockFactory::class); + $this->skuListsProcessorMock = $this->createMock(SkuListsProcessor::class); $this->plugin = new APISourceItemIndexerPlugin( - $this->configurableProductsSourceItemIndexer, - $this->getSourceItemsBySku, - $this->defaultSourceProvider, - $this->skuProvider + $this->getSkusByProductIdsMock, + $this->getStockIdsBySkusMock, + $this->skuListInStockFactoryMock, + $this->skuListsProcessorMock, ); - - parent::setUp(); } public function testAfterSave() { + $confId = 1; + $confSku = 'configurable1'; + $stockId = 2; + $childIds = [11, 12]; + $childSkus = ['sku-11', 'sku-12']; + $subject = $this->createMock(ProductResource::class); $result = $this->createMock(ProductResource::class); $object = $this->createMock(Product::class); @@ -78,44 +80,27 @@ public function testAfterSave() $typeInstance = $this->createMock(AbstractType::class); $typeInstance->expects($this->once()) ->method('getChildrenIds') - ->with(1) - ->willReturn( - [ - 0 => [11 => '11', 12 => '12'] - ] - ); + ->with($confId) + ->willReturn([$childIds]); + + $this->getSkusByProductIdsMock->expects($this->once()) + ->method('execute') + ->with($childIds) + ->willReturn($childSkus); + $this->getStockIdsBySkusMock->expects($this->once())->method('execute')->with($childSkus)->willReturn([2]); + $skuListInStockMock = $this->createMock(SkuListInStock::class); + $this->skuListInStockFactoryMock->expects($this->once()) + ->method('create') + ->with(['stockId' => $stockId, 'skuList' => [$confSku]]) + ->willReturn($skuListInStockMock); + $this->skuListsProcessorMock->expects($this->once())->method('reindexList')->with([$skuListInStockMock]); $object->expects($this->once())->method('getTypeInstance')->willReturn($typeInstance); - $object->expects($this->once())->method('getId')->willReturn(1); + $object->expects($this->once())->method('getId')->willReturn($confId); + $object->expects($this->once())->method('getSku')->willReturn($confSku); $object->expects($this->once())->method('cleanModelCache'); - $this->defaultSourceProvider->expects($this->exactly(2))->method('getCode')->willreturn('default'); - $childSourceItem1 = $this->getSourceItem(1); - $childSourceItem2 = $this->getSourceItem(2); - $this->skuProvider->expects($this->once()) - ->method('execute') - ->with([11 => '11', 12 => '12']) - ->willReturn([11 => 'child-1', 12 => 'child-2']); - $this->getSourceItemsBySku->expects($this->exactly(2)) - ->method('execute') - ->willReturnCallback(function ($arg) use ($childSourceItem1, $childSourceItem2) { - if ($arg == 'child-1') { - return [$childSourceItem1]; - } elseif ($arg == 'child-2') { - return [$childSourceItem2]; - } - }); - $this->configurableProductsSourceItemIndexer->expects($this->once())->method('executeList')->with([1, 2]); $interceptorResult = $this->plugin->afterSave($subject, $result, $object); $this->assertSame($interceptorResult, $result); } - - private function getSourceItem(int $returnValue): MockObject - { - $sourceItem = $this->createMock(SourceItem::class); - $sourceItem->expects($this->once())->method('getSourceCode')->willReturn('non-default-source'); - $sourceItem->expects($this->once())->method('getId')->willReturn($returnValue); - - return $sourceItem; - } } diff --git a/InventoryConfigurableProductIndexer/etc/di.xml b/InventoryConfigurableProductIndexer/etc/di.xml index 0beb1d0f4ed..b37de73a51c 100644 --- a/InventoryConfigurableProductIndexer/etc/di.xml +++ b/InventoryConfigurableProductIndexer/etc/di.xml @@ -7,23 +7,14 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <type name="Magento\InventoryConfigurableProductIndexer\Indexer\SourceItem\SourceItemIndexer"> + <type name="Magento\InventoryIndexer\Indexer\Stock\DataProvider"> <arguments> - <argument name="productsProvider" xsi:type="object">Magento\InventoryConfigurableProductIndexer\Indexer\SiblingProductsProvider</argument> - </arguments> - </type> - <type name="Magento\InventoryConfigurableProductIndexer\Indexer\SourceItem\SiblingSkuListInStockProvider"> - <arguments> - <argument name="tableNameSourceItem" xsi:type="const">Magento\Inventory\Model\ResourceModel\SourceItem::TABLE_NAME_SOURCE_ITEM</argument> - <argument name="tableNameStockSourceLink" xsi:type="const">Magento\Inventory\Model\ResourceModel\StockSourceLink::TABLE_NAME_STOCK_SOURCE_LINK</argument> - </arguments> - </type> - <type name="Magento\InventoryConfigurableProductIndexer\Indexer\SiblingProductsProvider"> - <arguments> - <argument name="selectBuilder" xsi:type="object">Magento\InventoryConfigurableProductIndexer\Indexer\SelectBuilder</argument> + <argument name="siblingSelectBuilders" xsi:type="array"> + <item name="configurable" xsi:type="object">Magento\InventoryConfigurableProductIndexer\Indexer\SelectBuilder</item> + </argument> </arguments> </type> - <type name="Magento\InventoryIndexer\Indexer\Stock\IndexDataFiller"> + <type name="Magento\InventoryIndexer\Indexer\SiblingProductsProvidersPool"> <arguments> <argument name="siblingProductsProviders" xsi:type="array"> <item name="configurable" xsi:type="object">Magento\InventoryConfigurableProductIndexer\Indexer\SiblingProductsProvider</item> diff --git a/InventoryGroupedProductIndexer/Indexer/SelectBuilder.php b/InventoryGroupedProductIndexer/Indexer/SelectBuilder.php index 1ea76b3bab7..307e3e0dcdb 100644 --- a/InventoryGroupedProductIndexer/Indexer/SelectBuilder.php +++ b/InventoryGroupedProductIndexer/Indexer/SelectBuilder.php @@ -13,8 +13,10 @@ use Magento\Framework\EntityManager\MetadataPool; use Magento\GroupedProduct\Model\ResourceModel\Product\Link; use Magento\InventoryIndexer\Indexer\IndexStructure; +use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameResolverInterface; /** @@ -22,42 +24,30 @@ */ class SelectBuilder implements SiblingSelectBuilderInterface { - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var IndexNameResolverInterface - */ - private $indexNameResolver; - - /** - * @var MetadataPool - */ - private $metadataPool; - /** * @param ResourceConnection $resourceConnection + * @param IndexNameBuilder $indexNameBuilder * @param IndexNameResolverInterface $indexNameResolver * @param MetadataPool $metadataPool */ public function __construct( - ResourceConnection $resourceConnection, - IndexNameResolverInterface $indexNameResolver, - MetadataPool $metadataPool, + private readonly ResourceConnection $resourceConnection, + private readonly IndexNameBuilder $indexNameBuilder, + private readonly IndexNameResolverInterface $indexNameResolver, + private readonly MetadataPool $metadataPool, ) { - $this->resourceConnection = $resourceConnection; - $this->indexNameResolver = $indexNameResolver; - $this->metadataPool = $metadataPool; } /** * @inheritdoc */ - public function getSelect(IndexName $indexName, array $skuList = []): Select + public function getSelect(int $stockId, array $skuList = [], IndexAlias $indexAlias = IndexAlias::MAIN): Select { $connection = $this->resourceConnection->getConnection(); + $indexName = $this->indexNameBuilder->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string) $stockId) + ->setAlias($indexAlias->value) + ->build(); $indexTableName = $this->indexNameResolver->resolveName($indexName); $metadata = $this->metadataPool->getMetadata(ProductInterface::class); $linkField = $metadata->getLinkField(); diff --git a/InventoryGroupedProductIndexer/Indexer/SiblingProductsProvider.php b/InventoryGroupedProductIndexer/Indexer/SiblingProductsProvider.php index aab9a0a2e98..f88abb479d9 100644 --- a/InventoryGroupedProductIndexer/Indexer/SiblingProductsProvider.php +++ b/InventoryGroupedProductIndexer/Indexer/SiblingProductsProvider.php @@ -11,20 +11,16 @@ use Magento\Framework\App\ResourceConnection; use Magento\Framework\EntityManager\MetadataPool; use Magento\InventoryIndexer\Indexer\SiblingProductsProviderInterface; -use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; class SiblingProductsProvider implements SiblingProductsProviderInterface { /** * @param ResourceConnection $resourceConnection * @param MetadataPool $metadataPool - * @param SiblingSelectBuilderInterface $selectBuilder */ public function __construct( private readonly ResourceConnection $resourceConnection, private readonly MetadataPool $metadataPool, - private readonly SiblingSelectBuilderInterface $selectBuilder, ) { } @@ -56,16 +52,4 @@ public function getSkus(array $skus): array return $siblingSkus; } - - /** - * @inheritdoc - */ - public function getData(IndexName $indexName, array $skuList = []): array - { - $connection = $this->resourceConnection->getConnection(); - $select = $this->selectBuilder->getSelect($indexName, $skuList); - $data = $connection->fetchAll($select); - - return $data; - } } diff --git a/InventoryGroupedProductIndexer/etc/di.xml b/InventoryGroupedProductIndexer/etc/di.xml index 121b5f4f18e..7b6246f32c7 100644 --- a/InventoryGroupedProductIndexer/etc/di.xml +++ b/InventoryGroupedProductIndexer/etc/di.xml @@ -7,12 +7,14 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - <type name="Magento\InventoryGroupedProductIndexer\Indexer\SiblingProductsProvider"> + <type name="Magento\InventoryIndexer\Indexer\Stock\DataProvider"> <arguments> - <argument name="selectBuilder" xsi:type="object">Magento\InventoryGroupedProductIndexer\Indexer\SelectBuilder</argument> + <argument name="siblingSelectBuilders" xsi:type="array"> + <item name="grouped" xsi:type="object">Magento\InventoryGroupedProductIndexer\Indexer\SelectBuilder</item> + </argument> </arguments> </type> - <type name="Magento\InventoryIndexer\Indexer\Stock\IndexDataFiller"> + <type name="Magento\InventoryIndexer\Indexer\SiblingProductsProvidersPool"> <arguments> <argument name="siblingProductsProviders" xsi:type="array"> <item name="grouped" xsi:type="object">Magento\InventoryGroupedProductIndexer\Indexer\SiblingProductsProvider</item> diff --git a/InventoryImportExport/Plugin/Import/SourceItemImporter.php b/InventoryImportExport/Plugin/Import/SourceItemImporter.php index 46477e23dfc..f1e8ff2f7ce 100644 --- a/InventoryImportExport/Plugin/Import/SourceItemImporter.php +++ b/InventoryImportExport/Plugin/Import/SourceItemImporter.php @@ -18,6 +18,7 @@ use Magento\InventoryApi\Api\SourceItemsSaveInterface; use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface; use Magento\InventoryCatalogApi\Model\IsSingleSourceModeInterface; +use Magento\InventoryIndexer\Indexer\CompositeProductsIndexer; use Magento\InventoryIndexer\Indexer\SourceItem\SourceItemIndexer; /** @@ -51,6 +52,7 @@ class SourceItemImporter * @param SkuStorage $skuStorage * @param SourceItemResourceModel $sourceItemResourceModel * @param SourceItemIndexer $sourceItemIndexer + * @param CompositeProductsIndexer $compositeProductsIndexer */ public function __construct( private readonly SourceItemsSaveInterface $sourceItemsSave, @@ -59,7 +61,8 @@ public function __construct( private readonly IsSingleSourceModeInterface $isSingleSourceMode, private readonly SkuStorage $skuStorage, private readonly SourceItemResourceModel $sourceItemResourceModel, - private readonly SourceItemIndexer $sourceItemIndexer + private readonly SourceItemIndexer $sourceItemIndexer, + private readonly CompositeProductsIndexer $compositeProductsIndexer, ) { } @@ -123,6 +126,10 @@ public function afterProcess( if (!empty($sourceItemIds)) { $this->sourceItemIndexer->executeList($sourceItemIds); } + + // Reindex composite products present in data. + // As they don't have their own source items, no reindex will be triggered automatically. + $this->compositeProductsIndexer->reindexList(array_keys($stockData)); } /** diff --git a/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php b/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php index eecde09c621..05fb898e240 100644 --- a/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php +++ b/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php @@ -447,6 +447,54 @@ public function testShouldReindexCustomStockWhenBackordersConfigChanges(): void $this->assertEquals(0, $getProductSalableQty->execute($sku, $stock2)); } + #[ + AppArea(\Magento\Framework\App\Area::AREA_ADMINHTML), + DataFixture(SourceFixture::class, ['source_code' => 'source2']), + DataFixture(StockFixture::class, as: 'stock2'), + DataFixture( + StockSourceLinksFixture::class, + [['stock_id' => '$stock2.stock_id$', 'source_code' => 'source2']] + ), + DataFixture( + StockSalesChannelsFixture::class, + ['stock_id' => '$stock2.stock_id$', 'sales_channels' => ['base']] + ), + DataFixture(ProductFixture::class, ['sku' => 'simple1']), + DataFixture( + SourceItemsFixture::class, + [ + ['sku' => 'simple1', 'source_code' => 'default', 'quantity' => 0], + ['sku' => 'simple1', 'source_code' => 'source2', 'quantity' => 100], + ] + ), + DataFixture( + CsvFileFixture::class, + [ + 'rows' => [ + ['product_websites', 'product_type', 'sku', 'name', 'associated_skus'], + ['base', 'grouped', 'grouped1', 'Grouped Product 1', 'simple1=5'], + ] + ], + 'grouped_product_import_file' + ), + ] + public function testShouldReindexCustomStockWhenCompositeProductImported(): void + { + $getStockItemData = Bootstrap::getObjectManager()->get(GetStockItemData::class); + $fixtures = DataFixtureStorageManager::getStorage(); + $stockId = (int) $fixtures->get('stock2')->getId(); + + $pathToFile = $fixtures->get('grouped_product_import_file')->getAbsolutePath(); + $productImporterModel = $this->getProductImporterModel($pathToFile); + $errors = $productImporterModel->validateData(); + self::assertEquals(0, $errors->getErrorsCount()); + $productImporterModel->importData(); + + $stockItemData = $getStockItemData->execute('grouped1', $stockId); + self::assertNotEmpty($stockItemData); + self::assertTrue((bool) $stockItemData[GetStockItemData::IS_SALABLE]); + } + /** * Process messages * @@ -508,12 +556,12 @@ private function buildDataArray(array $sourceItems): array * Return Product Importer Model for use with tests requires path to CSV import file * * @param string $pathToFile - * @param string $behavior + * @param string $behavior See Magento\ImportExport\Model\Source\Import\Behavior\Basic::toArray for proper mapping * @return Product */ private function getProductImporterModel( string $pathToFile, - string $behavior = Import::BEHAVIOR_ADD_UPDATE + string $behavior = Import::BEHAVIOR_APPEND ): Product { /** @var Filesystem\Directory\WriteInterface $directory */ $directory = $this->filesystem diff --git a/InventoryImportExport/Test/Unit/Plugin/Import/SourceItemImporterTest.php b/InventoryImportExport/Test/Unit/Plugin/Import/SourceItemImporterTest.php index 831982ef67a..66e99a688df 100644 --- a/InventoryImportExport/Test/Unit/Plugin/Import/SourceItemImporterTest.php +++ b/InventoryImportExport/Test/Unit/Plugin/Import/SourceItemImporterTest.php @@ -20,6 +20,7 @@ use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface; use Magento\InventoryCatalogApi\Model\IsSingleSourceModeInterface; use Magento\InventoryImportExport\Plugin\Import\SourceItemImporter; +use Magento\InventoryIndexer\Indexer\CompositeProductsIndexer; use Magento\InventoryIndexer\Indexer\SourceItem\SourceItemIndexer; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -71,6 +72,11 @@ class SourceItemImporterTest extends TestCase */ private $isSingleSourceModeMock; + /** + * @var CompositeProductsIndexer|MockObject + */ + private $compositeProductsIndexerMock; + /** * @var SkuStorage|MockObject */ @@ -81,26 +87,14 @@ class SourceItemImporterTest extends TestCase */ protected function setUp(): void { - $this->sourceItemsSaveMock = $this->getMockBuilder(SourceItemsSaveInterface::class) - ->disableOriginalConstructor() - ->getMock(); + $this->sourceItemsSaveMock = $this->createMock(SourceItemsSaveInterface::class); $this->sourceItemFactoryMock = $this->createMock(SourceItemInterfaceFactory::class); - $this->defaultSourceMock = $this->getMockBuilder(DefaultSourceProviderInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->sourceItemResourceModelMock = $this->getMockBuilder(SourceItem::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->stockItemProcessorMock = $this->getMockBuilder(StockItemProcessorInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->sourceItemMock = $this->getMockBuilder(SourceItemInterface::class) - ->disableOriginalConstructor() - ->getMock(); - + $this->defaultSourceMock = $this->createMock(DefaultSourceProviderInterface::class); + $this->sourceItemResourceModelMock = $this->createMock(SourceItem::class); + $this->stockItemProcessorMock = $this->createMock(StockItemProcessorInterface::class); + $this->sourceItemMock = $this->createMock(SourceItemInterface::class); $this->isSingleSourceModeMock = $this->createMock(IsSingleSourceModeInterface::class); + $this->compositeProductsIndexerMock = $this->createMock(CompositeProductsIndexer::class); $this->skuStorageMock = $this->createMock(SkuStorage::class); @@ -112,6 +106,7 @@ protected function setUp(): void $this->skuStorageMock, $this->sourceItemResourceModelMock, $this->createMock(SourceItemIndexer::class), + $this->compositeProductsIndexerMock, ); } @@ -182,6 +177,7 @@ public function testAfterImportForMultipleSource( $this->sourceItemsSaveMock->expects($this->once())->method('execute')->with([$this->sourceItemMock]) ->willReturnSelf(); } + $this->compositeProductsIndexerMock->expects($this->once())->method('reindexList')->with([$sku]); $this->plugin->afterProcess($this->stockItemProcessorMock, '', $stockData, []); } diff --git a/InventoryIndexer/Indexer/CompositeProductsIndexer.php b/InventoryIndexer/Indexer/CompositeProductsIndexer.php new file mode 100644 index 00000000000..83237760a5b --- /dev/null +++ b/InventoryIndexer/Indexer/CompositeProductsIndexer.php @@ -0,0 +1,85 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Indexer; + +use Magento\Catalog\Model\ProductTypes\ConfigInterface as ProductTypesConfig; +use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; +use Magento\InventoryCatalogApi\Model\GetChildrenSkusOfParentSkusInterface; +use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; + +class CompositeProductsIndexer +{ + /** + * @param ProductTypesConfig $productTypesConfig + * @param GetProductTypesBySkusInterface $getProductTypesBySkus + * @param GetChildrenSkusOfParentSkusInterface $getChildrenSkusOfParentSkus + * @param GetStockIdsBySkusInterface $getStockIdsBySkus + * @param SkuListInStockFactory $skuListInStockFactory + * @param SkuListsProcessor $skuListsProcessor + */ + public function __construct( + private readonly ProductTypesConfig $productTypesConfig, + private readonly GetProductTypesBySkusInterface $getProductTypesBySkus, + private readonly GetChildrenSkusOfParentSkusInterface $getChildrenSkusOfParentSkus, + private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, + private readonly SkuListInStockFactory $skuListInStockFactory, + private readonly SkuListsProcessor $skuListsProcessor, + ) { + } + + /** + * Reindex composite products present in the provided SKU list for stocks related to their child products. + * + * @param string[] $skus + * @return void + */ + public function reindexList(array $skus): void + { + if (!$skus) { + return; + } + + $compositeTypes = array_filter( + $this->productTypesConfig->getAll(), + fn (array $type) => ($type['composite'] ?? false) === true, + ); + + $productTypesBySkus = $this->getProductTypesBySkus->execute($skus); + $productSkusByTypes = array_fill_keys(array_unique(array_values($productTypesBySkus)), []); + foreach ($productTypesBySkus as $sku => $type) { + $productSkusByTypes[$type][] = $sku; + } + $compositeSkus = array_merge([], ...array_values(array_intersect_key($productSkusByTypes, $compositeTypes))); + if (!$compositeSkus) { + return; + } + + $parentStocks = []; + $childrenSkusOfParentSkus = $this->getChildrenSkusOfParentSkus->execute($compositeSkus); + foreach ($childrenSkusOfParentSkus as $parentSku => $childrenSkus) { + if (!$childrenSkus) { + continue; + } + + $stockIds = $this->getStockIdsBySkus->execute($childrenSkus); + foreach ($stockIds as $stockId) { + $parentStocks[$stockId][] = $parentSku; + } + } + + $skuListInStockList = []; + foreach ($parentStocks as $stockId => $parentSkus) { + $skuListInStockList[] = $this->skuListInStockFactory->create( + ['stockId' => $stockId, 'skuList' => $parentSkus] + ); + } + $this->skuListsProcessor->reindexList($skuListInStockList); + } +} diff --git a/InventoryIndexer/Indexer/SiblingProductsProviderInterface.php b/InventoryIndexer/Indexer/SiblingProductsProviderInterface.php index 986d111eaa2..64cbe0d5e1e 100644 --- a/InventoryIndexer/Indexer/SiblingProductsProviderInterface.php +++ b/InventoryIndexer/Indexer/SiblingProductsProviderInterface.php @@ -7,8 +7,6 @@ namespace Magento\InventoryIndexer\Indexer; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; - interface SiblingProductsProviderInterface { /** @@ -18,13 +16,4 @@ interface SiblingProductsProviderInterface * @return string[] */ public function getSkus(array $skus): array; - - /** - * Retrieve sibling product data based on their SKUs. - * - * @param IndexName $indexName - * @param array $skuList - * @return array - */ - public function getData(IndexName $indexName, array $skuList = []): array; } diff --git a/InventoryIndexer/Indexer/SiblingProductsProvidersPool.php b/InventoryIndexer/Indexer/SiblingProductsProvidersPool.php new file mode 100644 index 00000000000..82eb33a3523 --- /dev/null +++ b/InventoryIndexer/Indexer/SiblingProductsProvidersPool.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Indexer; + +class SiblingProductsProvidersPool +{ + /** + * @param SiblingProductsProviderInterface[] $siblingProductsProviders + */ + public function __construct( + private readonly array $siblingProductsProviders = [], + ) { + (fn (SiblingProductsProviderInterface ...$siblingProductsProviders) => $siblingProductsProviders)( + ...$this->siblingProductsProviders + ); + } + + /** + * Get sibling SKUs grouped by product type. + * + * @param string[] $skus + * @return array<string, string[]> + */ + public function getSiblingsGroupedByType(array $skus): array + { + if (!$skus) { + return []; + } + + $result = []; + foreach ($this->siblingProductsProviders as $productType => $siblingProductsProvider) { + $siblingSkus = $siblingProductsProvider->getSkus($skus); + if (!$siblingSkus) { + continue; + } + $result[$productType] = $siblingSkus; + } + + return $result; + } +} diff --git a/InventoryIndexer/Indexer/SiblingSelectBuilderInterface.php b/InventoryIndexer/Indexer/SiblingSelectBuilderInterface.php index 40985c74dac..531303366ad 100644 --- a/InventoryIndexer/Indexer/SiblingSelectBuilderInterface.php +++ b/InventoryIndexer/Indexer/SiblingSelectBuilderInterface.php @@ -8,16 +8,17 @@ namespace Magento\InventoryIndexer\Indexer; use Magento\Framework\DB\Select; -use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; interface SiblingSelectBuilderInterface { /** * Prepare select for sibling products. * - * @param IndexName $indexName - * @param array $skuList + * @param int $stockId + * @param string[] $skuList + * @param IndexAlias $indexAlias * @return Select */ - public function getSelect(IndexName $indexName, array $skuList = []): Select; + public function getSelect(int $stockId, array $skuList = [], IndexAlias $indexAlias = IndexAlias::MAIN): Select; } diff --git a/InventoryIndexer/Indexer/SourceItem/GetSkuListInStock.php b/InventoryIndexer/Indexer/SourceItem/GetSkuListInStock.php index c49fa1be4d1..df144cf814e 100644 --- a/InventoryIndexer/Indexer/SourceItem/GetSkuListInStock.php +++ b/InventoryIndexer/Indexer/SourceItem/GetSkuListInStock.php @@ -94,9 +94,7 @@ private function getStockIdToSkuList(array $items): array $skuListInStockList = []; foreach ($items as $stockId => $skuList) { /** @var SkuListInStock $skuListInStock */ - $skuListInStock = $this->skuListInStockFactory->create(); - $skuListInStock->setStockId((int)$stockId); - $skuListInStock->setSkuList($skuList); + $skuListInStock = $this->skuListInStockFactory->create(['stockId' => $stockId, 'skuList' => $skuList]); $skuListInStockList[] = $skuListInStock; } return $skuListInStockList; diff --git a/InventoryIndexer/Indexer/SourceItem/SkuListInStock.php b/InventoryIndexer/Indexer/SourceItem/SkuListInStock.php index 072c021db1e..40d86d32d0c 100644 --- a/InventoryIndexer/Indexer/SourceItem/SkuListInStock.php +++ b/InventoryIndexer/Indexer/SourceItem/SkuListInStock.php @@ -13,14 +13,14 @@ class SkuListInStock { /** - * @var int - */ - private $stockId; - - /** - * @var array + * @param int $stockId + * @param array $skuList */ - private $skuList; + public function __construct( + private int $stockId, + private array $skuList = [], + ) { + } /** * Returns the stock ID associated with the current instance. diff --git a/InventoryIndexer/Indexer/Stock/DataProvider.php b/InventoryIndexer/Indexer/Stock/DataProvider.php new file mode 100644 index 00000000000..538e5fc3ae8 --- /dev/null +++ b/InventoryIndexer/Indexer/Stock/DataProvider.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Indexer\Stock; + +use Magento\Framework\App\ResourceConnection; +use Magento\InventoryIndexer\Indexer\SelectBuilder; +use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; + +class DataProvider +{ + /** + * @param ResourceConnection $resourceConnection + * @param SelectBuilder $selectBuilder + * @param SiblingSelectBuilderInterface[] $siblingSelectBuilders + */ + public function __construct( + private readonly ResourceConnection $resourceConnection, + private readonly SelectBuilder $selectBuilder, + private readonly array $siblingSelectBuilders = [], + ) { + } + + /** + * Get data using default select builder. + * + * @param int $stockId + * @param string[] $skuList + * @return array<string, array{sku: string, quantity: float, is_salable: int}> + */ + public function getData(int $stockId, array $skuList = []): array + { + $select = $this->selectBuilder->getSelect($stockId, $skuList); + $data = $this->resourceConnection->getConnection()->fetchAll($select); + $data = array_column($data, null, 'sku'); + + return $data; + } + + /** + * Get data for sibling products of specified type. + * + * @param int $stockId + * @param string $productType + * @param string[] $skuList + * @param IndexAlias $indexAlias + * @return array<string, array{sku: string, quantity: float, is_salable: int}> + */ + public function getSiblingsData( + int $stockId, + string $productType, + array $skuList = [], + IndexAlias $indexAlias = IndexAlias::MAIN + ): array { + $siblingSelectBuilder = $this->siblingSelectBuilders[$productType]; + $select = $siblingSelectBuilder->getSelect($stockId, $skuList, $indexAlias); + $data = $this->resourceConnection->getConnection()->fetchAll($select); + $data = array_column($data, null, 'sku'); + + return $data; + } +} diff --git a/InventoryIndexer/Indexer/Stock/IndexDataFiller.php b/InventoryIndexer/Indexer/Stock/IndexDataFiller.php index 6896a5f8af6..6304e056b33 100644 --- a/InventoryIndexer/Indexer/Stock/IndexDataFiller.php +++ b/InventoryIndexer/Indexer/Stock/IndexDataFiller.php @@ -8,81 +8,96 @@ namespace Magento\InventoryIndexer\Indexer\Stock; use ArrayIterator; -use Magento\Framework\App\ResourceConnection; -use Magento\InventoryIndexer\Indexer\SelectBuilder; -use Magento\InventoryIndexer\Indexer\SiblingProductsProviderInterface; +use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; +use Magento\InventoryConfigurationApi\Model\GetAllowedProductTypesForSourceItemManagementInterface; +use Magento\InventoryIndexer\Indexer\SiblingProductsProvidersPool; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStock; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; class IndexDataFiller { /** - * @param ResourceConnection $resourceConnection - * @param SelectBuilder $selectBuilder + * @param ReservationsIndexTable $reservationsIndexTable + * @param PrepareReservationsIndexData $prepareReservationsIndexData + * @param GetProductTypesBySkusInterface $getProductTypesBySkus + * @param GetAllowedProductTypesForSourceItemManagementInterface $getSourceItemManagementProductTypes + * @param DataProvider $dataProvider * @param IndexHandlerInterface $indexStructureHandler - * @param SiblingProductsProviderInterface[] $siblingProductsProviders + * @param SiblingProductsProvidersPool $siblingProductsProvidersPool */ public function __construct( - private readonly ResourceConnection $resourceConnection, - private readonly SelectBuilder $selectBuilder, + private readonly ReservationsIndexTable $reservationsIndexTable, + private readonly PrepareReservationsIndexData $prepareReservationsIndexData, + private readonly GetProductTypesBySkusInterface $getProductTypesBySkus, + private readonly GetAllowedProductTypesForSourceItemManagementInterface $getSourceItemManagementProductTypes, + private readonly DataProvider $dataProvider, private readonly IndexHandlerInterface $indexStructureHandler, - private readonly array $siblingProductsProviders = [], + private readonly SiblingProductsProvidersPool $siblingProductsProvidersPool, ) { - (fn (SiblingProductsProviderInterface ...$siblingProductsProviders) => $siblingProductsProviders)( - ...$this->siblingProductsProviders - ); } /** * Fill index with data. * * @param IndexName $indexName - * @param int $stockId - * @param array $skuList + * @param SkuListInStock $skuListInStock + * @param string $connectionName * @return void */ - public function fillIndex(IndexName $indexName, int $stockId, array $skuList = []): void + public function fillIndex(IndexName $indexName, SkuListInStock $skuListInStock, string $connectionName): void { - $select = $this->selectBuilder->getSelect($stockId, $skuList); - $data = $this->resourceConnection->getConnection()->fetchAll($select); - if ($skuList) { - $this->indexStructureHandler->cleanIndex( - $indexName, - new ArrayIterator($skuList), - ResourceConnection::DEFAULT_CONNECTION - ); - } - $this->indexStructureHandler->saveIndex( - $indexName, - new ArrayIterator($data), - ResourceConnection::DEFAULT_CONNECTION - ); + $stockId = $skuListInStock->getStockId(); + $this->reservationsIndexTable->createTable($stockId); + $this->prepareReservationsIndexData->execute($stockId); - foreach ($this->siblingProductsProviders as $siblingProductsProvider) { - if (!empty($skuList)) { - // partial reindex - $siblingSkus = $siblingProductsProvider->getSkus($skuList); - if (!$siblingSkus) { - continue; - } - } else { - // full reindex - $siblingSkus = []; + $skuList = $skuListInStock->getSkuList(); + if ($skuList) { + $productTypesBySkus = $this->getProductTypesBySkus->execute($skuList); + $productSkusByTypes = array_fill_keys(array_unique(array_values($productTypesBySkus)), []); + foreach ($productTypesBySkus as $sku => $type) { + $productSkusByTypes[$type][] = $sku; } - $data = $siblingProductsProvider->getData($indexName, $siblingSkus); - if ($siblingSkus) { + $sourceItemManagementTypes = $this->getSourceItemManagementProductTypes->execute(); + $composableSkusByTypes = array_intersect_key($productSkusByTypes, array_flip($sourceItemManagementTypes)); + $compositeSkusByTypes = array_diff_key($productSkusByTypes, $composableSkusByTypes); + + $composableSkus = array_merge([], ...array_values($composableSkusByTypes)); + if ($composableSkus) { + $data = $this->dataProvider->getData($stockId, $composableSkus); $this->indexStructureHandler->cleanIndex( $indexName, - new ArrayIterator($siblingSkus), - ResourceConnection::DEFAULT_CONNECTION + new ArrayIterator($composableSkus), + $connectionName ); + $this->indexStructureHandler->saveIndex($indexName, new ArrayIterator($data), $connectionName); + } + } else { + $data = $this->dataProvider->getData($stockId); + $this->indexStructureHandler->saveIndex($indexName, new ArrayIterator($data), $connectionName); + $composableSkus = array_keys($data); + $compositeSkusByTypes = []; + } + + $siblingsGroupedByType = $this->siblingProductsProvidersPool->getSiblingsGroupedByType($composableSkus); + foreach ($siblingsGroupedByType as $productType => $siblingSkus) { + $compositeSkusByTypes[$productType] = isset($compositeSkusByTypes[$productType]) + ? array_keys(array_flip($compositeSkusByTypes[$productType]) + array_flip($siblingSkus)) + : $siblingSkus; + } + + $indexAlias = IndexAlias::from($indexName->getAlias()->getValue()); + foreach ($compositeSkusByTypes as $productType => $skus) { + $data = $this->dataProvider->getSiblingsData($stockId, $productType, $skus, $indexAlias); + if ($skuList) { + // Partial reindex. When full reindex, replica table is used, so no cleaning is required. + $this->indexStructureHandler->cleanIndex($indexName, new ArrayIterator($skus), $connectionName); } - $this->indexStructureHandler->saveIndex( - $indexName, - new ArrayIterator($data), - ResourceConnection::DEFAULT_CONNECTION - ); + $this->indexStructureHandler->saveIndex($indexName, new ArrayIterator($data), $connectionName); } + + $this->reservationsIndexTable->dropTable($stockId); } } diff --git a/InventoryIndexer/Indexer/Stock/SkuListsProcessor.php b/InventoryIndexer/Indexer/Stock/SkuListsProcessor.php index fe11cf0e09f..cf99fc6eb40 100644 --- a/InventoryIndexer/Indexer/Stock/SkuListsProcessor.php +++ b/InventoryIndexer/Indexer/Stock/SkuListsProcessor.php @@ -12,20 +12,23 @@ use Magento\InventoryIndexer\Indexer\InventoryIndexer; use Magento\InventoryIndexer\Indexer\SourceItem\CompositeProductProcessorInterface as ProductProcessor; use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStock; -use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; class SkuListsProcessor { + /** + * @var string + */ + private string $connectionName = ResourceConnection::DEFAULT_CONNECTION; + /** * @param GetSalableStatuses $getSalableStatuses * @param DefaultStockProviderInterface $defaultStockProvider * @param IndexNameBuilder $indexNameBuilder * @param IndexStructureInterface $indexStructure * @param IndexDataFiller $indexDataFiller - * @param ReservationsIndexTable $reservationsIndexTable - * @param PrepareReservationsIndexData $prepareReservationsIndexData * @param ProductProcessor[] $saleabilityChangesProcessorsPool */ public function __construct( @@ -34,8 +37,6 @@ public function __construct( private readonly IndexNameBuilder $indexNameBuilder, private readonly IndexStructureInterface $indexStructure, private readonly IndexDataFiller $indexDataFiller, - private readonly ReservationsIndexTable $reservationsIndexTable, - private readonly PrepareReservationsIndexData $prepareReservationsIndexData, private array $saleabilityChangesProcessorsPool = [], ) { // Sort processors by sort order @@ -64,19 +65,12 @@ public function reindexList(array $skuListInStockList): void $mainIndexName = $this->indexNameBuilder->setIndexId(InventoryIndexer::INDEXER_ID) ->addDimension('stock_', (string) $stockId) - ->setAlias(Alias::ALIAS_MAIN) + ->setAlias(IndexAlias::MAIN->value) ->build(); - if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { - $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); + if (!$this->indexStructure->isExist($mainIndexName, $this->connectionName)) { + $this->indexStructure->create($mainIndexName, $this->connectionName); } - - $this->reservationsIndexTable->createTable($stockId); - $this->prepareReservationsIndexData->execute($stockId); - - $skuList = $skuListInStock->getSkuList(); - $this->indexDataFiller->fillIndex($mainIndexName, $stockId, $skuList); - - $this->reservationsIndexTable->dropTable($stockId); + $this->indexDataFiller->fillIndex($mainIndexName, $skuListInStock, $this->connectionName); } // Store products salable statuses after reindex diff --git a/InventoryIndexer/Indexer/Stock/Strategy/Sync.php b/InventoryIndexer/Indexer/Stock/Strategy/Sync.php index 11e6f62589f..ebbcaa9f118 100644 --- a/InventoryIndexer/Indexer/Stock/Strategy/Sync.php +++ b/InventoryIndexer/Indexer/Stock/Strategy/Sync.php @@ -9,11 +9,10 @@ use Magento\Framework\App\ResourceConnection; use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface; use Magento\InventoryIndexer\Indexer\InventoryIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; use Magento\InventoryIndexer\Indexer\Stock\GetAllStockIds; use Magento\InventoryIndexer\Indexer\Stock\IndexDataFiller; -use Magento\InventoryIndexer\Indexer\Stock\PrepareReservationsIndexData; -use Magento\InventoryIndexer\Indexer\Stock\ReservationsIndexTable; -use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexStructureInterface; use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexTableSwitcherInterface; @@ -24,69 +23,28 @@ class Sync { /** - * @var GetAllStockIds + * @var string */ - private $getAllStockIds; + private string $connectionName = ResourceConnection::DEFAULT_CONNECTION; /** - * @var IndexStructureInterface - */ - private $indexStructure; - - /** - * @var IndexNameBuilder - */ - private $indexNameBuilder; - - /** - * @var IndexTableSwitcherInterface - */ - private $indexTableSwitcher; - - /** - * @var DefaultStockProviderInterface - */ - private $defaultStockProvider; - - /** - * @var ReservationsIndexTable - */ - private $reservationsIndexTable; - - /** - * @var PrepareReservationsIndexData - */ - private $prepareReservationsIndexData; - - /** - * $indexStructure is reserved name for construct variable in index internal mechanism - * * @param GetAllStockIds $getAllStockIds - * @param IndexStructureInterface $indexStructureHandler + * @param IndexStructureInterface $indexStructure * @param IndexNameBuilder $indexNameBuilder * @param IndexTableSwitcherInterface $indexTableSwitcher * @param DefaultStockProviderInterface $defaultStockProvider - * @param ReservationsIndexTable $reservationsIndexTable - * @param PrepareReservationsIndexData $prepareReservationsIndexData + * @param SkuListInStockFactory $skuListInStockFactory * @param IndexDataFiller $indexDataFiller */ public function __construct( - GetAllStockIds $getAllStockIds, - IndexStructureInterface $indexStructureHandler, - IndexNameBuilder $indexNameBuilder, - IndexTableSwitcherInterface $indexTableSwitcher, - DefaultStockProviderInterface $defaultStockProvider, - ReservationsIndexTable $reservationsIndexTable, - PrepareReservationsIndexData $prepareReservationsIndexData, + private readonly GetAllStockIds $getAllStockIds, + private readonly IndexStructureInterface $indexStructure, + private readonly IndexNameBuilder $indexNameBuilder, + private readonly IndexTableSwitcherInterface $indexTableSwitcher, + private readonly DefaultStockProviderInterface $defaultStockProvider, + private readonly SkuListInStockFactory $skuListInStockFactory, private readonly IndexDataFiller $indexDataFiller, ) { - $this->getAllStockIds = $getAllStockIds; - $this->indexStructure = $indexStructureHandler; - $this->indexNameBuilder = $indexNameBuilder; - $this->indexTableSwitcher = $indexTableSwitcher; - $this->defaultStockProvider = $defaultStockProvider; - $this->reservationsIndexTable = $reservationsIndexTable; - $this->prepareReservationsIndexData = $prepareReservationsIndexData; } /** @@ -124,34 +82,25 @@ public function executeList(array $stockIds): void continue; } - $replicaIndexName = $this->indexNameBuilder - ->setIndexId(InventoryIndexer::INDEXER_ID) - ->addDimension('stock_', (string)$stockId) - ->setAlias(Alias::ALIAS_REPLICA) + $replicaIndexName = $this->indexNameBuilder->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string) $stockId) + ->setAlias(IndexAlias::REPLICA->value) ->build(); + $this->indexStructure->delete($replicaIndexName, $this->connectionName); + $this->indexStructure->create($replicaIndexName, $this->connectionName); - $mainIndexName = $this->indexNameBuilder - ->setIndexId(InventoryIndexer::INDEXER_ID) - ->addDimension('stock_', (string)$stockId) - ->setAlias(Alias::ALIAS_MAIN) - ->build(); + $skuListInStock = $this->skuListInStockFactory->create(['stockId' => $stockId]); + $this->indexDataFiller->fillIndex($replicaIndexName, $skuListInStock, $this->connectionName); - $this->indexStructure->delete($replicaIndexName, ResourceConnection::DEFAULT_CONNECTION); - $this->indexStructure->create($replicaIndexName, ResourceConnection::DEFAULT_CONNECTION); - - if (!$this->indexStructure->isExist($mainIndexName, ResourceConnection::DEFAULT_CONNECTION)) { - $this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); + $mainIndexName = $this->indexNameBuilder->setIndexId(InventoryIndexer::INDEXER_ID) + ->addDimension('stock_', (string) $stockId) + ->setAlias(IndexAlias::MAIN->value) + ->build(); + if (!$this->indexStructure->isExist($mainIndexName, $this->connectionName)) { + $this->indexStructure->create($mainIndexName, $this->connectionName); } - - $this->reservationsIndexTable->createTable($stockId); - $this->prepareReservationsIndexData->execute($stockId); - - $this->indexDataFiller->fillIndex($replicaIndexName, $stockId); - - $this->indexTableSwitcher->switch($mainIndexName, ResourceConnection::DEFAULT_CONNECTION); - $this->indexStructure->delete($replicaIndexName, ResourceConnection::DEFAULT_CONNECTION); - - $this->reservationsIndexTable->dropTable($stockId); + $this->indexTableSwitcher->switch($mainIndexName, $this->connectionName); + $this->indexStructure->delete($replicaIndexName, $this->connectionName); } } } diff --git a/InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php b/InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php new file mode 100644 index 00000000000..53d97e1e13e --- /dev/null +++ b/InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php @@ -0,0 +1,138 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Test\Unit\Indexer; + +use Magento\Catalog\Model\ProductTypes\ConfigInterface as ProductTypesConfig; +use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; +use Magento\InventoryCatalogApi\Model\GetChildrenSkusOfParentSkusInterface; +use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; +use Magento\InventoryIndexer\Indexer\CompositeProductsIndexer; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStock; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; +use Magento\InventoryIndexer\Indexer\Stock\SkuListsProcessor; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class CompositeProductsIndexerTest extends TestCase +{ + /** + * @var GetProductTypesBySkusInterface|MockObject + */ + private $getProductTypesBySkusMock; + + /** + * @var GetChildrenSkusOfParentSkusInterface|MockObject + */ + private $getChildrenSkusOfParentSkusMock; + + /** + * @var GetStockIdsBySkusInterface|MockObject + */ + private $getStockIdsBySkusMock; + + /** + * @var SkuListInStockFactory|MockObject + */ + private $skuListInStockFactoryMock; + + /** + * @var SkuListsProcessor|MockObject + */ + private $skuListsProcessorMock; + + /** + * @var CompositeProductsIndexer + */ + private $indexer; + + protected function setUp(): void + { + $productTypesConfigMock = $this->createMock(ProductTypesConfig::class); + $this->getProductTypesBySkusMock = $this->createMock(GetProductTypesBySkusInterface::class); + $this->getChildrenSkusOfParentSkusMock = $this->createMock(GetChildrenSkusOfParentSkusInterface::class); + $this->getStockIdsBySkusMock = $this->createMock(GetStockIdsBySkusInterface::class); + $this->skuListInStockFactoryMock = $this->createMock(SkuListInStockFactory::class); + $this->skuListsProcessorMock = $this->createMock(SkuListsProcessor::class); + + $productTypesConfigMock->method('getAll') + ->willReturn([ + 'simple' => ['composite' => false], + 'configurable' => ['composite' => true], + 'bundle' => ['composite' => true], + 'grouped' => ['composite' => true], + ]); + + $this->indexer = new CompositeProductsIndexer( + $productTypesConfigMock, + $this->getProductTypesBySkusMock, + $this->getChildrenSkusOfParentSkusMock, + $this->getStockIdsBySkusMock, + $this->skuListInStockFactoryMock, + $this->skuListsProcessorMock, + ); + } + + public function testReindexListEmptyList(): void + { + $this->getProductTypesBySkusMock->expects(self::never())->method('execute'); + $this->skuListsProcessorMock->expects(self::never())->method('reindexList'); + $this->indexer->reindexList([]); + } + + public function testReindexListNoCompositePresent(): void + { + $skus = ['simple-1', 'simple-2']; + + $this->getProductTypesBySkusMock->expects(self::once())->method('execute')->with($skus) + ->willReturn([ + 'simple-1' => 'simple', + 'simple-2' => 'simple', + ]); + $this->getChildrenSkusOfParentSkusMock->expects(self::never())->method('execute'); + $this->skuListsProcessorMock->expects(self::never())->method('reindexList'); + + $this->indexer->reindexList($skus); + } + + public function testReindexList(): void + { + $skus = ['bundle-1', 'simple-2', 'configurable-3', 'grouped-4']; + + $this->getProductTypesBySkusMock->expects(self::once())->method('execute')->with($skus) + ->willReturn([ + 'bundle-1' => 'bundle', + 'simple-2' => 'simple', + 'configurable-3' => 'configurable', + 'grouped-4' => 'grouped', + ]); + $this->getChildrenSkusOfParentSkusMock->expects(self::once())->method('execute') + ->with(['bundle-1', 'configurable-3', 'grouped-4']) + ->willReturn([ + 'bundle1' => [], + 'configurable-3' => ['configurable1-red', 'configurable1-green'], + 'grouped-4' => ['simple1'], + ]); + $this->getStockIdsBySkusMock->expects(self::exactly(2))->method('execute') + ->willReturnMap([ + [['configurable1-red', 'configurable1-green'], [2]], + [['simple1'], [2,3]], + ]); + + $stock2Mock = $this->createMock(SkuListInStock::class); + $stock3Mock = $this->createMock(SkuListInStock::class); + $this->skuListInStockFactoryMock->expects(self::exactly(2))->method('create') + ->willReturnMap([ + [['stockId' => 2, 'skuList' => ['configurable-3', 'grouped-4']], $stock2Mock], + [['stockId' => 3, 'skuList' => ['grouped-4']], $stock3Mock], + ]); + $this->skuListsProcessorMock->expects(self::once())->method('reindexList') + ->with([$stock2Mock, $stock3Mock]); + + $this->indexer->reindexList($skus); + } +} diff --git a/InventoryIndexer/Test/Unit/Indexer/SiblingProductsProvidersPoolTest.php b/InventoryIndexer/Test/Unit/Indexer/SiblingProductsProvidersPoolTest.php new file mode 100644 index 00000000000..ab0c4b53308 --- /dev/null +++ b/InventoryIndexer/Test/Unit/Indexer/SiblingProductsProvidersPoolTest.php @@ -0,0 +1,50 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Test\Unit\Indexer; + +use Magento\InventoryIndexer\Indexer\SiblingProductsProviderInterface; +use Magento\InventoryIndexer\Indexer\SiblingProductsProvidersPool; +use PHPUnit\Framework\TestCase; + +class SiblingProductsProvidersPoolTest extends TestCase +{ + public function testGetSiblingsGroupedByTypeEmptyPool(): void + { + $model = new SiblingProductsProvidersPool([]); + self::assertCount(0, $model->getSiblingsGroupedByType([])); + } + + public function testGetSiblingsGroupedByTypeNoSiblings(): void + { + $skus = ['simple-1', 'simple-2']; + + $bundleProductsProvider = $this->createMock(SiblingProductsProviderInterface::class); + $bundleProductsProvider->expects(self::once())->method('getSkus')->willReturn($skus)->willReturn([]); + + $model = new SiblingProductsProvidersPool(['bundle' => $bundleProductsProvider]); + self::assertCount(0, $model->getSiblingsGroupedByType($skus)); + } + + public function testGetSiblingsGroupedByType(): void + { + $skus = ['simple-1', 'simple-2']; + + $bundleProductsProvider = $this->createMock(SiblingProductsProviderInterface::class); + $bundleProductsProvider->expects(self::once())->method('getSkus')->willReturn($skus) + ->willReturn(['bundle-1', 'bundle-2']); + $groupedProductsProvider = $this->createMock(SiblingProductsProviderInterface::class); + $groupedProductsProvider->expects(self::once())->method('getSkus')->willReturn($skus) + ->willReturn(['grouped-1']); + + $model = new SiblingProductsProvidersPool( + ['bundle' => $bundleProductsProvider, 'grouped' => $groupedProductsProvider] + ); + $result = $model->getSiblingsGroupedByType($skus); + self::assertEquals(['bundle' => ['bundle-1', 'bundle-2'], 'grouped' => ['grouped-1']], $result); + } +} diff --git a/InventoryIndexer/Test/Unit/Indexer/SourceItem/SkuListInStockTest.php b/InventoryIndexer/Test/Unit/Indexer/SourceItem/SkuListInStockTest.php new file mode 100644 index 00000000000..1f7138b6248 --- /dev/null +++ b/InventoryIndexer/Test/Unit/Indexer/SourceItem/SkuListInStockTest.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Test\Unit\Indexer\SourceItem; + +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStock; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[ + CoversClass(SkuListInStock::class), +] +class SkuListInStockTest extends TestCase +{ + public function testCreate(): void + { + $stockId = 2; + $skuList = ['sku1', 'sku2']; + $skuListInStock = new SkuListInStock($stockId, $skuList); + self::assertEquals($stockId, $skuListInStock->getStockId()); + self::assertEquals($skuList, $skuListInStock->getSkuList()); + } +} diff --git a/InventoryIndexer/Test/Unit/Indexer/Stock/DataProviderTest.php b/InventoryIndexer/Test/Unit/Indexer/Stock/DataProviderTest.php new file mode 100644 index 00000000000..3942281c9a0 --- /dev/null +++ b/InventoryIndexer/Test/Unit/Indexer/Stock/DataProviderTest.php @@ -0,0 +1,103 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Test\Unit\Indexer\Stock; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\DB\Select; +use Magento\InventoryIndexer\Indexer\SelectBuilder; +use Magento\InventoryIndexer\Indexer\SiblingSelectBuilderInterface; +use Magento\InventoryIndexer\Indexer\Stock\DataProvider; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +class DataProviderTest extends TestCase +{ + /** + * @var SelectBuilder|MockObject + */ + private $selectBuilderMock; + + /** + * @var SiblingSelectBuilderInterface|MockObject + */ + private $bundleSelectBuilderMock; + + /** + * @var SiblingSelectBuilderInterface|MockObject + */ + private $groupedSelectBuilderMock; + + /** + * @var AdapterInterface|MockObject + */ + private $connectionMock; + + /** + * @var DataProvider + */ + private $dataProvider; + + protected function setUp(): void + { + $resourceConnectionMock = $this->createMock(ResourceConnection::class); + $this->selectBuilderMock = $this->createMock(SelectBuilder::class); + $this->bundleSelectBuilderMock = $this->createMock(SiblingSelectBuilderInterface::class); + $this->groupedSelectBuilderMock = $this->createMock(SiblingSelectBuilderInterface::class); + + $this->connectionMock = $this->createMock(AdapterInterface::class); + $resourceConnectionMock->method('getConnection')->willReturn($this->connectionMock); + + $this->dataProvider = new DataProvider( + $resourceConnectionMock, + $this->selectBuilderMock, + ['bundle' => $this->bundleSelectBuilderMock, 'grouped' => $this->groupedSelectBuilderMock], + ); + } + + public function testGetData(): void + { + $stockId = 2; + $skuList = ['sku1', 'sku2']; + $data = [ + ['sku' => 'sku1', 'quantity' => 10, 'is_salable' => 1], + ['sku' => 'sku2', 'quantity' => 0, 'is_salable' => 0], + ]; + + $selectMock = $this->createMock(Select::class); + $this->selectBuilderMock->expects(self::once())->method('getSelect')->with($stockId)->willReturn($selectMock); + $this->connectionMock->expects(self::once())->method('fetchAll')->with($selectMock)->willReturn($data); + $this->bundleSelectBuilderMock->expects(self::never())->method('getSelect'); + $this->groupedSelectBuilderMock->expects(self::never())->method('getSelect'); + + $result = $this->dataProvider->getData($stockId, $skuList); + self::assertEquals(array_combine($skuList, $data), $result); + } + + public function testGetSiblingsData(): void + { + $stockId = 2; + $skuList = ['bundle1', 'bundle2']; + $data = [ + ['sku' => 'bundle1', 'quantity' => 10, 'is_salable' => 1], + ['sku' => 'bundle2', 'quantity' => 0, 'is_salable' => 0], + ]; + + $selectMock = $this->createMock(Select::class); + $this->bundleSelectBuilderMock->expects(self::once()) + ->method('getSelect') + ->with($stockId, $skuList) + ->willReturn($selectMock); + $this->connectionMock->expects(self::once())->method('fetchAll')->with($selectMock)->willReturn($data); + $this->selectBuilderMock->expects(self::never())->method('getSelect'); + $this->groupedSelectBuilderMock->expects(self::never())->method('getSelect'); + + $result = $this->dataProvider->getSiblingsData($stockId, 'bundle', $skuList); + self::assertEquals(array_combine($skuList, $data), $result); + } +} diff --git a/InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php b/InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php new file mode 100644 index 00000000000..23a1600f172 --- /dev/null +++ b/InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php @@ -0,0 +1,373 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryIndexer\Test\Unit\Indexer\Stock; + +use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; +use Magento\InventoryConfigurationApi\Model\GetAllowedProductTypesForSourceItemManagementInterface; +use Magento\InventoryIndexer\Indexer\SiblingProductsProvidersPool; +use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStock; +use Magento\InventoryIndexer\Indexer\Stock\DataProvider; +use Magento\InventoryIndexer\Indexer\Stock\IndexDataFiller; +use Magento\InventoryIndexer\Indexer\Stock\PrepareReservationsIndexData; +use Magento\InventoryIndexer\Indexer\Stock\ReservationsIndexTable; +use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias as IndexAliasModel; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexAlias; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface; +use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexName; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +#[ + CoversClass(IndexDataFiller::class), +] +class IndexDataFillerTest extends TestCase +{ + /** + * @var ReservationsIndexTable|MockObject + */ + private $reservationsIndexTableMock; + + /** + * @var PrepareReservationsIndexData|MockObject + */ + private $prepareReservationsIndexDataMock; + + /** + * @var GetProductTypesBySkusInterface|MockObject + */ + private $getProductTypesBySkusMock; + + /** + * @var DataProvider|MockObject + */ + private $dataProviderMock; + + /** + * @var IndexHandlerInterface|MockObject + */ + private $indexStructureHandlerMock; + + /** + * @var SiblingProductsProvidersPool|MockObject + */ + private $siblingProductsProvidersPoolMock; + + /** + * @var string + */ + private $connectionName; + + /** + * @var IndexDataFiller + */ + private $indexDataFiller; + + protected function setUp(): void + { + $this->reservationsIndexTableMock = $this->createMock(ReservationsIndexTable::class); + $this->prepareReservationsIndexDataMock = $this->createMock(PrepareReservationsIndexData::class); + $this->getProductTypesBySkusMock = $this->createMock(GetProductTypesBySkusInterface::class); + $getSourceItemManagementProductTypesMock = $this->createMock( + GetAllowedProductTypesForSourceItemManagementInterface::class + ); + $this->dataProviderMock = $this->createMock(DataProvider::class); + $this->indexStructureHandlerMock = $this->createMock(IndexHandlerInterface::class); + $this->siblingProductsProvidersPoolMock = $this->createMock(SiblingProductsProvidersPool::class); + + $getSourceItemManagementProductTypesMock->method('execute')->willReturn(['simple']); + $this->connectionName = 'default'; + + $this->indexDataFiller = new IndexDataFiller( + $this->reservationsIndexTableMock, + $this->prepareReservationsIndexDataMock, + $this->getProductTypesBySkusMock, + $getSourceItemManagementProductTypesMock, + $this->dataProviderMock, + $this->indexStructureHandlerMock, + $this->siblingProductsProvidersPoolMock, + ); + } + + public function testFillIndexSimpleProducts(): void + { + $stockId = 2; + $simpleSkuList = ['simple-1', 'simple-2']; + + $aliasMock = $this->createMock(IndexAliasModel::class); + $aliasMock->method('getValue')->willReturn(IndexAlias::MAIN->value); + $indexNameMock = $this->createMock(IndexName::class); + $indexNameMock->method('getAlias')->willReturn($aliasMock); + $skuListInStockMock = $this->createMock(SkuListInStock::class); + $skuListInStockMock->method('getStockId')->willReturn($stockId); + $skuListInStockMock->method('getSkuList')->willReturn($simpleSkuList); + + $this->reservationsIndexTableMock->expects(self::once())->method('createTable')->with($stockId); + $this->prepareReservationsIndexDataMock->expects(self::once())->method('execute')->with($stockId); + $this->reservationsIndexTableMock->expects(self::once())->method('dropTable')->with($stockId); + + $typesBySkus = [ + 'simple-1' => 'simple', + 'simple-2' => 'simple', + ]; + $this->getProductTypesBySkusMock->expects(self::once()) + ->method('execute') + ->with($simpleSkuList) + ->willReturn($typesBySkus); + $data = [ + 'simple-1' => ['sku' => 'simple-1', 'quantity' => 10, 'is_salable' => true], + 'simple-2' => ['sku' => 'simple-2', 'quantity' => 0, 'is_salable' => false], + ]; + $this->dataProviderMock->expects(self::once()) + ->method('getData') + ->with($stockId, $simpleSkuList) + ->willReturn($data); + $this->indexStructureHandlerMock->expects(self::once()) + ->method('cleanIndex') + ->with($indexNameMock, new \ArrayIterator($simpleSkuList), $this->connectionName); + $this->indexStructureHandlerMock->expects(self::once()) + ->method('saveIndex') + ->with($indexNameMock, new \ArrayIterator($data), $this->connectionName); + $this->siblingProductsProvidersPoolMock->expects(self::once()) + ->method('getSiblingsGroupedByType') + ->with($simpleSkuList) + ->willReturn([]); + $this->dataProviderMock->expects(self::never())->method('getSiblingsData'); + + $this->indexDataFiller->fillIndex($indexNameMock, $skuListInStockMock, $this->connectionName); + } + + public function testFillIndexSimpleProductsWithParents(): void + { + $stockId = 2; + $simpleSkuList = ['simple-1', 'simple-2']; + + $aliasMock = $this->createMock(IndexAliasModel::class); + $aliasMock->method('getValue')->willReturn(IndexAlias::MAIN->value); + $indexNameMock = $this->createMock(IndexName::class); + $indexNameMock->method('getAlias')->willReturn($aliasMock); + $skuListInStockMock = $this->createMock(SkuListInStock::class); + $skuListInStockMock->method('getStockId')->willReturn($stockId); + $skuListInStockMock->method('getSkuList')->willReturn($simpleSkuList); + + $this->reservationsIndexTableMock->expects(self::once())->method('createTable')->with($stockId); + $this->prepareReservationsIndexDataMock->expects(self::once())->method('execute')->with($stockId); + $this->reservationsIndexTableMock->expects(self::once())->method('dropTable')->with($stockId); + + $typesBySkus = [ + 'simple-1' => 'simple', + 'simple-2' => 'simple', + ]; + $this->getProductTypesBySkusMock->expects(self::once()) + ->method('execute') + ->with($simpleSkuList) + ->willReturn($typesBySkus); + $simpleData = [ + 'simple-1' => ['sku' => 'simple-1', 'quantity' => 10, 'is_salable' => true], + 'simple-2' => ['sku' => 'simple-2', 'quantity' => 0, 'is_salable' => false], + ]; + $this->dataProviderMock->expects(self::once()) + ->method('getData') + ->with($stockId, $simpleSkuList) + ->willReturn($simpleData); + $compositeSkuList = ['grouped-1', 'grouped-2']; + $this->siblingProductsProvidersPoolMock->expects(self::once()) + ->method('getSiblingsGroupedByType') + ->with($simpleSkuList) + ->willReturn(['grouped' => $compositeSkuList]); + $compositeData = [ + 'grouped-1' => ['sku' => 'grouped-1', 'quantity' => 15, 'is_salable' => true], + 'grouped-2' => ['sku' => 'grouped-2', 'quantity' => 0, 'is_salable' => false], + ]; + $this->dataProviderMock->expects(self::once()) + ->method('getSiblingsData') + ->with($stockId, 'grouped', $compositeSkuList, IndexAlias::MAIN) + ->willReturn($compositeData); + + $this->indexStructureHandlerMock->expects(self::exactly(2)) + ->method('cleanIndex') + ->willReturnCallback( + function (IndexName $indexName, \Traversable $skus, string $connectionName) + use ($indexNameMock, $simpleSkuList, $compositeSkuList) + { + static $callIndex = 0; + $callIndex++; + self::assertEquals($indexNameMock, $indexName); + self::assertEquals($this->connectionName, $connectionName); + if ($callIndex === 1) { + self::assertEquals(new \ArrayIterator($simpleSkuList), $skus); + } elseif ($callIndex === 2) { + self::assertEquals(new \ArrayIterator($compositeSkuList), $skus); + } + } + ); + $this->indexStructureHandlerMock->expects(self::exactly(2)) + ->method('saveIndex') + ->willReturnCallback( + function (IndexName $indexName, \Traversable $data, string $connectionName) + use ($indexNameMock, $simpleData, $compositeData) + { + static $callIndex = 0; + $callIndex++; + self::assertEquals($indexNameMock, $indexName); + self::assertEquals($this->connectionName, $connectionName); + if ($callIndex === 1) { + self::assertEquals(new \ArrayIterator($simpleData), $data); + } elseif ($callIndex === 2) { + self::assertEquals(new \ArrayIterator($compositeData), $data); + } + } + ); + + $this->indexDataFiller->fillIndex($indexNameMock, $skuListInStockMock, $this->connectionName); + } + + public function testFillIndexCompositeProducts(): void + { + $stockId = 2; + $compositeSkuList = ['bundle-1', 'bundle-2']; + + $aliasMock = $this->createMock(IndexAliasModel::class); + $aliasMock->method('getValue')->willReturn(IndexAlias::MAIN->value); + $indexNameMock = $this->createMock(IndexName::class); + $indexNameMock->method('getAlias')->willReturn($aliasMock); + $skuListInStockMock = $this->createMock(SkuListInStock::class); + $skuListInStockMock->method('getStockId')->willReturn($stockId); + $skuListInStockMock->method('getSkuList')->willReturn($compositeSkuList); + + $this->reservationsIndexTableMock->expects(self::once())->method('createTable')->with($stockId); + $this->prepareReservationsIndexDataMock->expects(self::once())->method('execute')->with($stockId); + $this->reservationsIndexTableMock->expects(self::once())->method('dropTable')->with($stockId); + + $typesBySkus = [ + 'bundle-1' => 'bundle', + 'bundle-2' => 'bundle', + ]; + $this->getProductTypesBySkusMock->expects(self::once()) + ->method('execute') + ->with($compositeSkuList) + ->willReturn($typesBySkus); + $this->dataProviderMock->expects(self::never())->method('getData'); + $this->siblingProductsProvidersPoolMock->expects(self::once()) + ->method('getSiblingsGroupedByType') + ->with([]) + ->willReturn([]); + $data = [ + 'bundle-1' => ['sku' => 'bundle-1', 'quantity' => 0, 'is_salable' => false], + 'bundle-2' => ['sku' => 'bundle-2', 'quantity' => 20, 'is_salable' => true], + ]; + $this->dataProviderMock->expects(self::once()) + ->method('getSiblingsData') + ->with($stockId, 'bundle', $compositeSkuList, IndexAlias::MAIN) + ->willReturn($data); + $this->indexStructureHandlerMock->expects(self::once()) + ->method('cleanIndex') + ->with($indexNameMock, new \ArrayIterator($compositeSkuList), $this->connectionName); + $this->indexStructureHandlerMock->expects(self::once()) + ->method('saveIndex') + ->with($indexNameMock, new \ArrayIterator($data), $this->connectionName); + + $this->indexDataFiller->fillIndex($indexNameMock, $skuListInStockMock, $this->connectionName); + } + + public function testFillIndexMixedProducts(): void + { + $stockId = 2; + $skuList = ['bundle-1', 'simple-1', 'simple-2', 'grouped-1']; + + $aliasMock = $this->createMock(IndexAliasModel::class); + $aliasMock->method('getValue')->willReturn(IndexAlias::MAIN->value); + $indexNameMock = $this->createMock(IndexName::class); + $indexNameMock->method('getAlias')->willReturn($aliasMock); + $skuListInStockMock = $this->createMock(SkuListInStock::class); + $skuListInStockMock->method('getStockId')->willReturn($stockId); + $skuListInStockMock->method('getSkuList')->willReturn($skuList); + + $this->reservationsIndexTableMock->expects(self::once())->method('createTable')->with($stockId); + $this->prepareReservationsIndexDataMock->expects(self::once())->method('execute')->with($stockId); + $this->reservationsIndexTableMock->expects(self::once())->method('dropTable')->with($stockId); + + $typesBySkus = [ + 'bundle-1' => 'bundle', + 'simple-1' => 'simple', + 'simple-2' => 'simple', + 'grouped-1' => 'grouped', + ]; + $this->getProductTypesBySkusMock->expects(self::once()) + ->method('execute') + ->with($skuList) + ->willReturn($typesBySkus); + $simpleData = [ + 'simple-1' => ['sku' => 'simple-1', 'quantity' => 10, 'is_salable' => true], + 'simple-2' => ['sku' => 'simple-2', 'quantity' => 0, 'is_salable' => false], + ]; + $this->dataProviderMock->expects(self::once()) + ->method('getData') + ->with($stockId, ['simple-1', 'simple-2']) + ->willReturn($simpleData); + $this->siblingProductsProvidersPoolMock->expects(self::once()) + ->method('getSiblingsGroupedByType') + ->with(['simple-1', 'simple-2']) + ->willReturn(['bundle' => ['bundle-2', 'bundle-3'], 'grouped' => ['grouped-1', 'grouped-2']]); + $bundleData = [ + 'bundle-1' => ['sku' => 'bundle-1', 'quantity' => 15, 'is_salable' => true], + 'bundle-2' => ['sku' => 'bundle-2', 'quantity' => 25, 'is_salable' => true], + 'bundle-3' => ['sku' => 'bundle-3', 'quantity' => 0, 'is_salable' => false], + ]; + $groupedData = [ + 'grouped-1' => ['sku' => 'grouped-1', 'quantity' => 0, 'is_salable' => false], + 'grouped-2' => ['sku' => 'grouped-2', 'quantity' => 30, 'is_salable' => true], + ]; + $this->dataProviderMock->expects(self::exactly(2)) + ->method('getSiblingsData') + ->willReturnMap([ + [$stockId, 'bundle', ['bundle-1', 'bundle-2', 'bundle-3'], IndexAlias::MAIN, $bundleData], + [$stockId, 'grouped', ['grouped-1', 'grouped-2'], IndexAlias::MAIN, $groupedData], + ]); + + $this->indexStructureHandlerMock->expects(self::exactly(3)) + ->method('cleanIndex') + ->willReturnCallback( + function (IndexName $indexName, \Traversable $skus, string $connectionName) use ($indexNameMock) + { + static $callIndex = 0; + $callIndex++; + self::assertEquals($indexNameMock, $indexName); + self::assertEquals($this->connectionName, $connectionName); + if ($callIndex === 1) { + self::assertEquals(new \ArrayIterator(['simple-1', 'simple-2']), $skus); + } elseif ($callIndex === 2) { + self::assertEquals(new \ArrayIterator(['bundle-1', 'bundle-2', 'bundle-3']), $skus); + } elseif ($callIndex === 3) { + self::assertEquals(new \ArrayIterator(['grouped-1', 'grouped-2']), $skus); + } + } + ); + $this->indexStructureHandlerMock->expects(self::exactly(3)) + ->method('saveIndex') + ->willReturnCallback( + function (IndexName $indexName, \Traversable $data, string $connectionName) + use ($indexNameMock, $simpleData, $bundleData, $groupedData) + { + static $callIndex = 0; + $callIndex++; + self::assertEquals($indexNameMock, $indexName); + self::assertEquals($this->connectionName, $connectionName); + if ($callIndex === 1) { + self::assertEquals(new \ArrayIterator($simpleData), $data); + } elseif ($callIndex === 2) { + self::assertEquals(new \ArrayIterator($bundleData), $data); + } elseif ($callIndex === 3) { + self::assertEquals(new \ArrayIterator($groupedData), $data); + } + } + ); + + $this->indexDataFiller->fillIndex($indexNameMock, $skuListInStockMock, $this->connectionName); + } +} diff --git a/InventoryMultiDimensionalIndexerApi/Model/Alias.php b/InventoryMultiDimensionalIndexerApi/Model/Alias.php index 2cca5dc1cf9..ecd1d357d66 100644 --- a/InventoryMultiDimensionalIndexerApi/Model/Alias.php +++ b/InventoryMultiDimensionalIndexerApi/Model/Alias.php @@ -19,20 +19,24 @@ class Alias { /** * Replica index alias + * + * @deprecated + * @see IndexAlias::REPLICA */ - public const ALIAS_REPLICA = 'replica'; + public const ALIAS_REPLICA = IndexAlias::REPLICA->value; /** * Main index alias + * + * @deprecated + * @see IndexAlias::MAIN */ - public const ALIAS_MAIN = 'main'; + public const ALIAS_MAIN = IndexAlias::MAIN->value; /** - * One of self::ALIAS_* - * - * @var string + * @var IndexAlias */ - private $value; + private IndexAlias $value; /** * @param string $value One of self::ALIAS_* @@ -40,10 +44,11 @@ class Alias */ public function __construct(string $value) { - if ($value !== self::ALIAS_REPLICA && $value !== self::ALIAS_MAIN) { + try { + $this->value = IndexAlias::from($value); + } catch (\ValueError) { throw new LocalizedException(new Phrase('Wrong value %value for alias', ['value' => $value])); } - $this->value = $value; } /** @@ -53,6 +58,6 @@ public function __construct(string $value) */ public function getValue(): string { - return $this->value; + return $this->value->value; } } diff --git a/InventoryMultiDimensionalIndexerApi/Model/IndexAlias.php b/InventoryMultiDimensionalIndexerApi/Model/IndexAlias.php new file mode 100644 index 00000000000..a07ff1588dd --- /dev/null +++ b/InventoryMultiDimensionalIndexerApi/Model/IndexAlias.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryMultiDimensionalIndexerApi\Model; + +/** + * Aliases for inventory indexer. + */ +enum IndexAlias: string +{ + case MAIN = 'main'; + case REPLICA = 'replica'; +} From 0067e067e1f85d3609bf72a0253c6b1cca6c2c8c Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <dhorytskyi@magento.com> Date: Mon, 6 Oct 2025 13:53:48 -0500 Subject: [PATCH 34/46] ACP2E-4233: Grouped product incorrectly shows as Out of Stock on PDP after import from CSV when child is assigned to custom source/stock (fixed after manual reindex) --- .../Indexer/Stock/IndexDataFillerTest.php | 54 +++++++++---------- InventoryIndexer/composer.json | 3 +- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php b/InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php index 23a1600f172..4ebb22aaf18 100644 --- a/InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php +++ b/InventoryIndexer/Test/Unit/Indexer/Stock/IndexDataFillerTest.php @@ -23,6 +23,9 @@ use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ #[ CoversClass(IndexDataFiller::class), ] @@ -192,34 +195,30 @@ public function testFillIndexSimpleProductsWithParents(): void $this->indexStructureHandlerMock->expects(self::exactly(2)) ->method('cleanIndex') ->willReturnCallback( - function (IndexName $indexName, \Traversable $skus, string $connectionName) - use ($indexNameMock, $simpleSkuList, $compositeSkuList) - { + function (...$args) use ($indexNameMock, $simpleSkuList, $compositeSkuList) { static $callIndex = 0; $callIndex++; - self::assertEquals($indexNameMock, $indexName); - self::assertEquals($this->connectionName, $connectionName); + self::assertEquals($indexNameMock, $args[0]); + self::assertEquals($this->connectionName, $args[2]); if ($callIndex === 1) { - self::assertEquals(new \ArrayIterator($simpleSkuList), $skus); + self::assertEquals(new \ArrayIterator($simpleSkuList), $args[1]); } elseif ($callIndex === 2) { - self::assertEquals(new \ArrayIterator($compositeSkuList), $skus); + self::assertEquals(new \ArrayIterator($compositeSkuList), $args[1]); } } ); $this->indexStructureHandlerMock->expects(self::exactly(2)) ->method('saveIndex') ->willReturnCallback( - function (IndexName $indexName, \Traversable $data, string $connectionName) - use ($indexNameMock, $simpleData, $compositeData) - { + function (...$args) use ($indexNameMock, $simpleData, $compositeData) { static $callIndex = 0; $callIndex++; - self::assertEquals($indexNameMock, $indexName); - self::assertEquals($this->connectionName, $connectionName); + self::assertEquals($indexNameMock, $args[0]); + self::assertEquals($this->connectionName, $args[2]); if ($callIndex === 1) { - self::assertEquals(new \ArrayIterator($simpleData), $data); + self::assertEquals(new \ArrayIterator($simpleData), $args[1]); } elseif ($callIndex === 2) { - self::assertEquals(new \ArrayIterator($compositeData), $data); + self::assertEquals(new \ArrayIterator($compositeData), $args[1]); } } ); @@ -333,37 +332,34 @@ public function testFillIndexMixedProducts(): void $this->indexStructureHandlerMock->expects(self::exactly(3)) ->method('cleanIndex') ->willReturnCallback( - function (IndexName $indexName, \Traversable $skus, string $connectionName) use ($indexNameMock) - { + function (...$args) use ($indexNameMock) { static $callIndex = 0; $callIndex++; - self::assertEquals($indexNameMock, $indexName); - self::assertEquals($this->connectionName, $connectionName); + self::assertEquals($indexNameMock, $args[0]); + self::assertEquals($this->connectionName, $args[2]); if ($callIndex === 1) { - self::assertEquals(new \ArrayIterator(['simple-1', 'simple-2']), $skus); + self::assertEquals(new \ArrayIterator(['simple-1', 'simple-2']), $args[1]); } elseif ($callIndex === 2) { - self::assertEquals(new \ArrayIterator(['bundle-1', 'bundle-2', 'bundle-3']), $skus); + self::assertEquals(new \ArrayIterator(['bundle-1', 'bundle-2', 'bundle-3']), $args[1]); } elseif ($callIndex === 3) { - self::assertEquals(new \ArrayIterator(['grouped-1', 'grouped-2']), $skus); + self::assertEquals(new \ArrayIterator(['grouped-1', 'grouped-2']), $args[1]); } } ); $this->indexStructureHandlerMock->expects(self::exactly(3)) ->method('saveIndex') ->willReturnCallback( - function (IndexName $indexName, \Traversable $data, string $connectionName) - use ($indexNameMock, $simpleData, $bundleData, $groupedData) - { + function (...$args) use ($indexNameMock, $simpleData, $bundleData, $groupedData) { static $callIndex = 0; $callIndex++; - self::assertEquals($indexNameMock, $indexName); - self::assertEquals($this->connectionName, $connectionName); + self::assertEquals($indexNameMock, $args[0]); + self::assertEquals($this->connectionName, $args[2]); if ($callIndex === 1) { - self::assertEquals(new \ArrayIterator($simpleData), $data); + self::assertEquals(new \ArrayIterator($simpleData), $args[1]); } elseif ($callIndex === 2) { - self::assertEquals(new \ArrayIterator($bundleData), $data); + self::assertEquals(new \ArrayIterator($bundleData), $args[1]); } elseif ($callIndex === 3) { - self::assertEquals(new \ArrayIterator($groupedData), $data); + self::assertEquals(new \ArrayIterator($groupedData), $args[1]); } } ); diff --git a/InventoryIndexer/composer.json b/InventoryIndexer/composer.json index 6dc72272d9b..034a88a6602 100644 --- a/InventoryIndexer/composer.json +++ b/InventoryIndexer/composer.json @@ -11,7 +11,8 @@ "magento/module-inventory-catalog-api": "*", "magento/module-inventory-configuration-api": "*", "magento/module-inventory-sales-api": "*", - "magento/module-inventory-sales": "*" + "magento/module-inventory-sales": "*", + "magento/module-catalog": "*" }, "suggest": { "magento/module-catalog": "*" From b36328a27aef96afa2924f23e39cbc336eecc277 Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <dhorytskyi@magento.com> Date: Mon, 6 Oct 2025 14:25:50 -0500 Subject: [PATCH 35/46] ACP2E-4233: Grouped product incorrectly shows as Out of Stock on PDP after import from CSV when child is assigned to custom source/stock (fixed after manual reindex) --- .../CompositeProductTypesProviderTest.php | 24 +++++++++++++ .../Model/CompositeProductTypesProvider.php | 35 +++++++++++++++++++ InventoryCatalog/etc/di.xml | 2 ++ ...CompositeProductTypesProviderInterface.php | 18 ++++++++++ .../CompositeProductTypesProviderTest.php | 24 +++++++++++++ .../CompositeProductTypesProviderTest.php | 24 +++++++++++++ .../Indexer/CompositeProductsIndexer.php | 15 ++++---- .../Indexer/CompositeProductsIndexerTest.php | 15 +++----- InventoryIndexer/composer.json | 3 +- 9 files changed, 139 insertions(+), 21 deletions(-) create mode 100644 InventoryBundleProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php create mode 100644 InventoryCatalog/Model/CompositeProductTypesProvider.php create mode 100644 InventoryCatalogApi/Model/CompositeProductTypesProviderInterface.php create mode 100644 InventoryConfigurableProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php create mode 100644 InventoryGroupedProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php diff --git a/InventoryBundleProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php b/InventoryBundleProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php new file mode 100644 index 00000000000..9d37cec51a5 --- /dev/null +++ b/InventoryBundleProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryBundleProduct\Test\Integration\Model; + +use Magento\Bundle\Model\Product\Type as BundleType; +use Magento\InventoryCatalogApi\Model\CompositeProductTypesProviderInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +class CompositeProductTypesProviderTest extends TestCase +{ + public function testExecute(): void + { + $compositeProductTypesProvider = Bootstrap::getObjectManager() + ->create(CompositeProductTypesProviderInterface::class); + $compositeProductTypes = $compositeProductTypesProvider->execute(); + self::assertContains(BundleType::TYPE_CODE, $compositeProductTypes); + } +} diff --git a/InventoryCatalog/Model/CompositeProductTypesProvider.php b/InventoryCatalog/Model/CompositeProductTypesProvider.php new file mode 100644 index 00000000000..1e7b39c13e5 --- /dev/null +++ b/InventoryCatalog/Model/CompositeProductTypesProvider.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryCatalog\Model; + +use Magento\Catalog\Model\ProductTypes\ConfigInterface as ProductTypesConfig; +use Magento\InventoryCatalogApi\Model\CompositeProductTypesProviderInterface; + +class CompositeProductTypesProvider implements CompositeProductTypesProviderInterface +{ + /** + * @param ProductTypesConfig $productTypesConfig + */ + public function __construct( + private readonly ProductTypesConfig $productTypesConfig, + ) { + } + + /** + * @inheritdoc + */ + public function execute(): array + { + $compositeTypes = array_filter( + $this->productTypesConfig->getAll(), + fn (array $type) => ($type['composite'] ?? false) === true, + ); + + return array_keys($compositeTypes); + } +} diff --git a/InventoryCatalog/etc/di.xml b/InventoryCatalog/etc/di.xml index 4ef4b84f88d..cf5c11428a6 100644 --- a/InventoryCatalog/etc/di.xml +++ b/InventoryCatalog/etc/di.xml @@ -17,6 +17,8 @@ <preference for="Magento\InventoryCatalogApi\Model\SourceItemsProcessorInterface" type="Magento\InventoryCatalog\Model\SourceItemsProcessor"/> <preference for="Magento\CatalogInventory\Model\StockStatusApplierInterface" type="Magento\InventoryCatalog\Model\StockStatusApplier" /> <preference for="Magento\CatalogInventory\Observer\SaveInventoryDataObserver" type="Magento\InventoryCatalog\Observer\SaveInventoryDataObserver"/> + <preference for="Magento\InventoryCatalogApi\Model\CompositeProductTypesProviderInterface" type="Magento\InventoryCatalog\Model\CompositeProductTypesProvider"/> + <type name="Magento\InventoryApi\Api\StockRepositoryInterface"> <plugin name="prevent_default_stock_deleting" type="Magento\InventoryCatalog\Plugin\InventoryApi\StockRepository\PreventDeleting\DefaultStockPlugin"/> diff --git a/InventoryCatalogApi/Model/CompositeProductTypesProviderInterface.php b/InventoryCatalogApi/Model/CompositeProductTypesProviderInterface.php new file mode 100644 index 00000000000..fabe1b74c2b --- /dev/null +++ b/InventoryCatalogApi/Model/CompositeProductTypesProviderInterface.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryCatalogApi\Model; + +interface CompositeProductTypesProviderInterface +{ + /** + * Returns composite product types. + * + * @return string[] + */ + public function execute(): array; +} diff --git a/InventoryConfigurableProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php b/InventoryConfigurableProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php new file mode 100644 index 00000000000..2115c764819 --- /dev/null +++ b/InventoryConfigurableProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryConfigurableProduct\Test\Integration\Model; + +use Magento\ConfigurableProduct\Model\Product\Type\Configurable as ConfigurableType; +use Magento\InventoryCatalogApi\Model\CompositeProductTypesProviderInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +class CompositeProductTypesProviderTest extends TestCase +{ + public function testExecute(): void + { + $compositeProductTypesProvider = Bootstrap::getObjectManager() + ->create(CompositeProductTypesProviderInterface::class); + $compositeProductTypes = $compositeProductTypesProvider->execute(); + self::assertContains(ConfigurableType::TYPE_CODE, $compositeProductTypes); + } +} diff --git a/InventoryGroupedProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php b/InventoryGroupedProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php new file mode 100644 index 00000000000..2f6b1d5843b --- /dev/null +++ b/InventoryGroupedProduct/Test/Integration/Model/CompositeProductTypesProviderTest.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +declare(strict_types=1); + +namespace Magento\InventoryGroupedProduct\Test\Integration\Model; + +use Magento\GroupedProduct\Model\Product\Type\Grouped as GroupedType; +use Magento\InventoryCatalogApi\Model\CompositeProductTypesProviderInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +class CompositeProductTypesProviderTest extends TestCase +{ + public function testExecute(): void + { + $compositeProductTypesProvider = Bootstrap::getObjectManager() + ->create(CompositeProductTypesProviderInterface::class); + $compositeProductTypes = $compositeProductTypesProvider->execute(); + self::assertContains(GroupedType::TYPE_CODE, $compositeProductTypes); + } +} diff --git a/InventoryIndexer/Indexer/CompositeProductsIndexer.php b/InventoryIndexer/Indexer/CompositeProductsIndexer.php index 83237760a5b..d514f55b737 100644 --- a/InventoryIndexer/Indexer/CompositeProductsIndexer.php +++ b/InventoryIndexer/Indexer/CompositeProductsIndexer.php @@ -7,8 +7,8 @@ namespace Magento\InventoryIndexer\Indexer; -use Magento\Catalog\Model\ProductTypes\ConfigInterface as ProductTypesConfig; use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; +use Magento\InventoryCatalogApi\Model\CompositeProductTypesProviderInterface; use Magento\InventoryCatalogApi\Model\GetChildrenSkusOfParentSkusInterface; use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; use Magento\InventoryIndexer\Indexer\SourceItem\SkuListInStockFactory; @@ -17,7 +17,7 @@ class CompositeProductsIndexer { /** - * @param ProductTypesConfig $productTypesConfig + * @param CompositeProductTypesProviderInterface $compositeProductTypesProvider * @param GetProductTypesBySkusInterface $getProductTypesBySkus * @param GetChildrenSkusOfParentSkusInterface $getChildrenSkusOfParentSkus * @param GetStockIdsBySkusInterface $getStockIdsBySkus @@ -25,7 +25,7 @@ class CompositeProductsIndexer * @param SkuListsProcessor $skuListsProcessor */ public function __construct( - private readonly ProductTypesConfig $productTypesConfig, + private readonly CompositeProductTypesProviderInterface $compositeProductTypesProvider, private readonly GetProductTypesBySkusInterface $getProductTypesBySkus, private readonly GetChildrenSkusOfParentSkusInterface $getChildrenSkusOfParentSkus, private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, @@ -46,17 +46,14 @@ public function reindexList(array $skus): void return; } - $compositeTypes = array_filter( - $this->productTypesConfig->getAll(), - fn (array $type) => ($type['composite'] ?? false) === true, - ); - $productTypesBySkus = $this->getProductTypesBySkus->execute($skus); $productSkusByTypes = array_fill_keys(array_unique(array_values($productTypesBySkus)), []); foreach ($productTypesBySkus as $sku => $type) { $productSkusByTypes[$type][] = $sku; } - $compositeSkus = array_merge([], ...array_values(array_intersect_key($productSkusByTypes, $compositeTypes))); + $compositeTypes = $this->compositeProductTypesProvider->execute(); + $compositeSkusByTypes = array_intersect_key($productSkusByTypes, array_flip($compositeTypes)); + $compositeSkus = array_merge([], ...array_values($compositeSkusByTypes)); if (!$compositeSkus) { return; } diff --git a/InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php b/InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php index 53d97e1e13e..0e26200cf2e 100644 --- a/InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php +++ b/InventoryIndexer/Test/Unit/Indexer/CompositeProductsIndexerTest.php @@ -7,8 +7,8 @@ namespace Magento\InventoryIndexer\Test\Unit\Indexer; -use Magento\Catalog\Model\ProductTypes\ConfigInterface as ProductTypesConfig; use Magento\InventoryApi\Model\GetStockIdsBySkusInterface; +use Magento\InventoryCatalogApi\Model\CompositeProductTypesProviderInterface; use Magento\InventoryCatalogApi\Model\GetChildrenSkusOfParentSkusInterface; use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; use Magento\InventoryIndexer\Indexer\CompositeProductsIndexer; @@ -52,23 +52,18 @@ class CompositeProductsIndexerTest extends TestCase protected function setUp(): void { - $productTypesConfigMock = $this->createMock(ProductTypesConfig::class); + $compositeProductTypesProviderMock = $this->createMock(CompositeProductTypesProviderInterface::class); $this->getProductTypesBySkusMock = $this->createMock(GetProductTypesBySkusInterface::class); $this->getChildrenSkusOfParentSkusMock = $this->createMock(GetChildrenSkusOfParentSkusInterface::class); $this->getStockIdsBySkusMock = $this->createMock(GetStockIdsBySkusInterface::class); $this->skuListInStockFactoryMock = $this->createMock(SkuListInStockFactory::class); $this->skuListsProcessorMock = $this->createMock(SkuListsProcessor::class); - $productTypesConfigMock->method('getAll') - ->willReturn([ - 'simple' => ['composite' => false], - 'configurable' => ['composite' => true], - 'bundle' => ['composite' => true], - 'grouped' => ['composite' => true], - ]); + $compositeProductTypesProviderMock->method('execute') + ->willReturn(['bundle', 'configurable', 'grouped']); $this->indexer = new CompositeProductsIndexer( - $productTypesConfigMock, + $compositeProductTypesProviderMock, $this->getProductTypesBySkusMock, $this->getChildrenSkusOfParentSkusMock, $this->getStockIdsBySkusMock, diff --git a/InventoryIndexer/composer.json b/InventoryIndexer/composer.json index 034a88a6602..6dc72272d9b 100644 --- a/InventoryIndexer/composer.json +++ b/InventoryIndexer/composer.json @@ -11,8 +11,7 @@ "magento/module-inventory-catalog-api": "*", "magento/module-inventory-configuration-api": "*", "magento/module-inventory-sales-api": "*", - "magento/module-inventory-sales": "*", - "magento/module-catalog": "*" + "magento/module-inventory-sales": "*" }, "suggest": { "magento/module-catalog": "*" From 0d11b666d7d92e5f1c0764d312ddc8f301bfd2ec Mon Sep 17 00:00:00 2001 From: Dmytro Horytskyi <dhorytskyi@magento.com> Date: Mon, 6 Oct 2025 18:34:36 -0500 Subject: [PATCH 36/46] ACP2E-4233: Grouped product incorrectly shows as Out of Stock on PDP after import from CSV when child is assigned to custom source/stock (fixed after manual reindex) --- .../Strategy/Sync/APISourceItemIndexerPlugin.php | 10 ++++++++-- .../Strategy/Sync/APISourceItemIndexerPluginTest.php | 11 ++++++++--- .../Plugin/Import/SourceItemImporter.php | 5 ++++- .../Test/Integration/Model/Import/ProductTest.php | 4 ++-- InventoryIndexer/Indexer/CompositeProductsIndexer.php | 4 ++-- 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php index 6969a0c2a6b..47ef91f04b2 100644 --- a/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php +++ b/InventoryConfigurableProductIndexer/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPlugin.php @@ -19,12 +19,14 @@ class APISourceItemIndexerPlugin { /** + * @param Configurable $configurableType * @param GetSkusByProductIdsInterface $getSkusByProductIds * @param GetStockIdsBySkusInterface $getStockIdsBySkus * @param SkuListInStockFactory $skuListInStockFactory * @param SkuListsProcessor $skuListsProcessor */ public function __construct( + private readonly Configurable $configurableType, private readonly GetSkusByProductIdsInterface $getSkusByProductIds, private readonly GetStockIdsBySkusInterface $getStockIdsBySkus, private readonly SkuListInStockFactory $skuListInStockFactory, @@ -51,8 +53,12 @@ public function afterSave( return $result; } - $childProductIds = $product->getTypeInstance()->getChildrenIds($product->getId()); - $childProductSkus = $this->getSkusByProductIds->execute($childProductIds[0]); + $childProductIds = $this->configurableType->getChildrenIds($product->getId())[0]; + if (!$childProductIds) { + return $result; + } + + $childProductSkus = $this->getSkusByProductIds->execute($childProductIds); $stockIds = $this->getStockIdsBySkus->execute($childProductSkus); if ($stockIds) { $skuListInStockList = []; diff --git a/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php b/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php index 5e395fa53ca..c42b6e6acf0 100644 --- a/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php +++ b/InventoryConfigurableProductIndexer/Test/Unit/Plugin/InventoryIndexer/Indexer/SourceItem/Strategy/Sync/APISourceItemIndexerPluginTest.php @@ -29,6 +29,11 @@ class APISourceItemIndexerPluginTest extends TestCase */ private $plugin; + /** + * @var Configurable|MockObject + */ + private $typeInstanceMock; + /** * @var GetSkusByProductIdsInterface|MockObject */ @@ -53,11 +58,13 @@ protected function setUp(): void { parent::setUp(); + $this->typeInstanceMock = $this->createMock(Configurable::class); $this->getSkusByProductIdsMock = $this->createMock(GetSkusByProductIdsInterface::class); $this->getStockIdsBySkusMock = $this->createMock(GetStockIdsBySkusInterface::class); $this->skuListInStockFactoryMock = $this->createMock(SkuListInStockFactory::class); $this->skuListsProcessorMock = $this->createMock(SkuListsProcessor::class); $this->plugin = new APISourceItemIndexerPlugin( + $this->typeInstanceMock, $this->getSkusByProductIdsMock, $this->getStockIdsBySkusMock, $this->skuListInStockFactoryMock, @@ -77,8 +84,7 @@ public function testAfterSave() $result = $this->createMock(ProductResource::class); $object = $this->createMock(Product::class); $object->expects($this->once())->method('getTypeId')->willReturn(Configurable::TYPE_CODE); - $typeInstance = $this->createMock(AbstractType::class); - $typeInstance->expects($this->once()) + $this->typeInstanceMock->expects($this->once()) ->method('getChildrenIds') ->with($confId) ->willReturn([$childIds]); @@ -95,7 +101,6 @@ public function testAfterSave() ->willReturn($skuListInStockMock); $this->skuListsProcessorMock->expects($this->once())->method('reindexList')->with([$skuListInStockMock]); - $object->expects($this->once())->method('getTypeInstance')->willReturn($typeInstance); $object->expects($this->once())->method('getId')->willReturn($confId); $object->expects($this->once())->method('getSku')->willReturn($confSku); $object->expects($this->once())->method('cleanModelCache'); diff --git a/InventoryImportExport/Plugin/Import/SourceItemImporter.php b/InventoryImportExport/Plugin/Import/SourceItemImporter.php index f1e8ff2f7ce..46e667e94ab 100644 --- a/InventoryImportExport/Plugin/Import/SourceItemImporter.php +++ b/InventoryImportExport/Plugin/Import/SourceItemImporter.php @@ -87,6 +87,8 @@ public function afterProcess( array $importedData ): void { $sourceItems = []; + $skus = []; + $isSingleSourceMode = $this->isSingleSourceMode->execute(); // No need to load existing source items in single source mode as we know the only source is 'default' $existingSourceItemsBySKU = $isSingleSourceMode ? [] : $this->getSourceItems(array_keys($stockData)); @@ -94,6 +96,7 @@ public function afterProcess( $sourceItemIds = []; foreach ($stockData as $sku => $stockDatum) { $sku = (string)$sku; + $skus[] = $sku; $sources = $existingSourceItemsBySKU[$sku] ?? []; $isQtyExplicitlySet = (bool) ($importedData[$sku]['qty'] ?? false); $hasDefaultSource = isset($sources[$defaultSourceCode]); @@ -129,7 +132,7 @@ public function afterProcess( // Reindex composite products present in data. // As they don't have their own source items, no reindex will be triggered automatically. - $this->compositeProductsIndexer->reindexList(array_keys($stockData)); + $this->compositeProductsIndexer->reindexList($skus); } /** diff --git a/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php b/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php index 05fb898e240..53a912118d1 100644 --- a/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php +++ b/InventoryImportExport/Test/Integration/Model/Import/ProductTest.php @@ -471,8 +471,8 @@ public function testShouldReindexCustomStockWhenBackordersConfigChanges(): void CsvFileFixture::class, [ 'rows' => [ - ['product_websites', 'product_type', 'sku', 'name', 'associated_skus'], - ['base', 'grouped', 'grouped1', 'Grouped Product 1', 'simple1=5'], + ['product_type', 'sku', 'name', 'product_websites', 'associated_skus', 'attribute_set_code'], + ['grouped', 'grouped1', 'Grouped Product 1', 'base', 'simple1=5', 'Default'], ] ], 'grouped_product_import_file' diff --git a/InventoryIndexer/Indexer/CompositeProductsIndexer.php b/InventoryIndexer/Indexer/CompositeProductsIndexer.php index d514f55b737..dd6240576c9 100644 --- a/InventoryIndexer/Indexer/CompositeProductsIndexer.php +++ b/InventoryIndexer/Indexer/CompositeProductsIndexer.php @@ -49,7 +49,7 @@ public function reindexList(array $skus): void $productTypesBySkus = $this->getProductTypesBySkus->execute($skus); $productSkusByTypes = array_fill_keys(array_unique(array_values($productTypesBySkus)), []); foreach ($productTypesBySkus as $sku => $type) { - $productSkusByTypes[$type][] = $sku; + $productSkusByTypes[$type][] = (string) $sku; } $compositeTypes = $this->compositeProductTypesProvider->execute(); $compositeSkusByTypes = array_intersect_key($productSkusByTypes, array_flip($compositeTypes)); @@ -67,7 +67,7 @@ public function reindexList(array $skus): void $stockIds = $this->getStockIdsBySkus->execute($childrenSkus); foreach ($stockIds as $stockId) { - $parentStocks[$stockId][] = $parentSku; + $parentStocks[$stockId][] = (string) $parentSku; } } From 642f8f7d27a2cf16dda29f4c625c71747f3db127 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Wed, 8 Oct 2025 12:21:01 +0300 Subject: [PATCH 37/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- .../web/js/model/pickup-locations-service.js | 4 +-- .../ShippingInformationManagementPlugin.php | 27 +++---------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js index 15d77450c57..2984a502c0c 100644 --- a/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js +++ b/InventoryInStorePickupFrontend/view/frontend/web/js/model/pickup-locations-service.js @@ -144,8 +144,8 @@ define([ addressConverter.quoteAddressToFormAddressData(address) ); } - if (!billingAddress || this.isBillingAddressIncomplete(billingAddress)) { - selectBillingAddressAction(address); + if (!billingAddress) { + quote.billingAddress(null); checkoutDataResolver.resolveBillingAddress(); } }, diff --git a/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php b/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php index 84880e20597..50ed793153e 100644 --- a/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php +++ b/InventoryInStorePickupQuote/Plugin/Checkout/ShippingInformationManagementPlugin.php @@ -33,7 +33,7 @@ public function beforeSaveAddressInformation( $address = $addressInformation->getShippingAddress(); $billingAddress = $addressInformation->getBillingAddress(); - if ($this->isPickupStoreShipping($address) && $this->isBillingAddressIncomplete($billingAddress)) { + if (!$this->isPickupStoreShipping($address) && $this->isBillingAddressCompletelyNull($billingAddress)) { $addressInformation->setBillingAddress($address); } @@ -59,32 +59,13 @@ private function isPickupStoreShipping(?AddressInterface $shippingAddress): bool } /** - * Check if billing address is incomplete (missing required fields) + * Check if billing address is completely null (not set at all) * * @param AddressInterface|null $billingAddress * @return bool */ - private function isBillingAddressIncomplete(?AddressInterface $billingAddress): bool + private function isBillingAddressCompletelyNull(?AddressInterface $billingAddress): bool { - if (!$billingAddress) { - return true; - } - $requiredFields = [ - 'firstname', - 'lastname', - 'street', - 'city', - 'postcode', - 'telephone', - 'regionId', - 'countryId' - ]; - foreach ($requiredFields as $field) { - $getter = 'get' . ucfirst($field); - if (method_exists($billingAddress, $getter) && !$billingAddress->$getter()) { - return true; - } - } - return false; + return $billingAddress === null; } } From 2c4fa7a9dff10ad061cff280c2ad33d57af80dc9 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Thu, 9 Oct 2025 14:59:11 +0300 Subject: [PATCH 38/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- ...tCustomerFillBillingAddressActionGroup.xml | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml index c58f25e1490..4d37364168b 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml @@ -7,12 +7,28 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" extends="GuestCheckoutFillNewBillingAddressActionGroup"> + <actionGroup name="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup"> <annotations> <description>Fill guest customer billing address for store pickup shipping method.</description> </annotations> - <remove keyForRemoval="waitForEmailField"/> - <remove keyForRemoval="enterEmail"/> + <arguments> + <argument name="customerVar"/> + <argument name="customerAddressVar"/> + </arguments> + + <!-- The billing form is already in edit mode, so just wait for it to be visible --> + <waitForElementVisible selector="{{CheckoutPaymentSection.guestFirstName}}" stepKey="waitForBillingFormVisible"/> + + <!-- Fill the form fields --> + <fillField selector="{{CheckoutPaymentSection.guestFirstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutPaymentSection.guestLastName}}" userInput="{{customerVar.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutPaymentSection.guestStreet}}" userInput="{{customerAddressVar.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutPaymentSection.guestCity}}" userInput="{{customerAddressVar.city}}" stepKey="enterCity"/> + <selectOption selector="{{CheckoutPaymentSection.guestRegion}}" userInput="{{customerAddressVar.state}}" stepKey="selectRegion"/> + <fillField selector="{{CheckoutPaymentSection.guestPostcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> + <fillField selector="{{CheckoutPaymentSection.guestTelephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> + + <!-- Save the address --> <click selector="{{CheckoutPaymentSection.update}}" stepKey="updateAddress"/> <waitForLoadingMaskToDisappear stepKey="waitForAddressUpdate"/> </actionGroup> From adcf44cb571a484b2cde6674dd5a20aa6900c501 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Thu, 9 Oct 2025 18:13:36 +0300 Subject: [PATCH 39/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- .../AdminNotifyCustomerForPickupOrderBundleProductTest.xml | 5 ++++- ...inNotifyCustomerForPickupOrderConfigurableProductTest.xml | 5 ++++- .../AdminNotifyCustomerForPickupOrderGroupedProductTest.xml | 5 ++++- ...eOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml | 5 ++++- ...ssFilledAutomaticallyWithSimpleProductCustomStockTest.xml | 2 +- ...ateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml | 5 ++++- 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml index 3c3efc9aad5..b9d0ab73e78 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml @@ -114,7 +114,10 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <argument name="customerVar" value="Simple_US_Customer"/> + <argument name="customerAddressVar" value="US_Address_TX"/> + </actionGroup> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml index 8cc03868df7..b8774508aa2 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml @@ -114,7 +114,10 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <argument name="customerVar" value="Simple_US_Customer"/> + <argument name="customerAddressVar" value="US_Address_TX"/> + </actionGroup> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml index c1f48075df8..654aa21c8d3 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml @@ -115,7 +115,10 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <argument name="customerVar" value="Simple_US_Customer"/> + <argument name="customerAddressVar" value="US_Address_TX"/> + </actionGroup> <waitForElementVisible selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" time="30" stepKey="waitForOrderSummaryBlock"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml index b2e57984ed8..d3905ebbf0b 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/GuestCustomerPlaceOrderWithPickupInStoreMethodWithGoogleAPIEnabledTest.xml @@ -132,7 +132,10 @@ <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="clickCheckMoneyOrderPayment"/> <!--Fill Shipping address --> - <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <argument name="customerVar" value="Simple_US_Customer"/> + <argument name="customerAddressVar" value="US_Address_TX"/> + </actionGroup> <!--Click on place order --> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> <waitForElement selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="waitForOrderNumber"/> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml index 6ded15d08f3..1f8808f414a 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontBillingAddressFilledAutomaticallyWithSimpleProductCustomStockTest.xml @@ -104,7 +104,7 @@ </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> <actionGroup ref="StorefrontAssertPaymentInformationActionGroup" stepKey="verifyPaymentInformation"> - <argument name="address" value="{{US_Address_California.street[0]}}"/> + <argument name="address" value="{{US_Address_TX.street[0]}}"/> </actionGroup> </test> </tests> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml index dd56c24b332..1c983db04a7 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml @@ -132,7 +132,10 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <comment userInput="Billing address step is no longer needed for in-store pickup" stepKey="fillAddress"/> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <argument name="customerVar" value="Simple_US_Customer"/> + <argument name="customerAddressVar" value="US_Address_TX"/> + </actionGroup> <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrder"/> <actionGroup ref="ClickPlaceOrderActionGroup" stepKey="clickOnPlaceOrder"/> <waitForPageLoad stepKey="waitForSuccess"/> From 22c769218800de6caa391979d503c967a49b6bc4 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Fri, 10 Oct 2025 21:12:54 +0300 Subject: [PATCH 40/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- ...hippingInformationManagementPluginTest.php | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php index e318bf1aebf..e1a6b638d03 100644 --- a/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php +++ b/InventoryInStorePickupQuote/Test/Unit/Plugin/Checkout/ShippingInformationManagementPluginTest.php @@ -90,7 +90,7 @@ protected function setUp(): void } /** - * Test beforeSaveAddressInformation when billing address is incomplete + * Test beforeSaveAddressInformation when it's pickup store with incomplete billing * * @return void */ @@ -104,18 +104,13 @@ public function testBeforeSaveAddressInformationPickupStoreIncompleteBilling(): $this->extensionAttributes->expects($this->once()) ->method('getPickupLocationCode') ->willReturn($pickupLocationCode); - $this->billingAddress->expects($this->once()) - ->method('getFirstname') - ->willReturn(null); $this->addressInformation->expects($this->once()) ->method('getShippingAddress') ->willReturn($this->shippingAddress); $this->addressInformation->expects($this->once()) ->method('getBillingAddress') ->willReturn($this->billingAddress); - $this->addressInformation->expects($this->once()) - ->method('setBillingAddress') - ->with($this->shippingAddress); + $this->addressInformation->expects($this->never())->method('setBillingAddress'); $result = $this->plugin->beforeSaveAddressInformation( $this->subject, $cartId, @@ -125,7 +120,7 @@ public function testBeforeSaveAddressInformationPickupStoreIncompleteBilling(): } /** - * Test beforeSaveAddressInformation when billing address is complete + * Test beforeSaveAddressInformation when it's pickup store with complete billing * * @return void */ @@ -139,14 +134,6 @@ public function testBeforeSaveAddressInformationPickupStoreCompleteBilling(): vo $this->extensionAttributes->expects($this->once()) ->method('getPickupLocationCode') ->willReturn($pickupLocationCode); - $this->billingAddress->expects($this->once())->method('getFirstname')->willReturn('Test'); - $this->billingAddress->expects($this->once())->method('getLastname')->willReturn('Test'); - $this->billingAddress->expects($this->once())->method('getStreet')->willReturn(['123 Test Street']); - $this->billingAddress->expects($this->once())->method('getCity')->willReturn('Austin'); - $this->billingAddress->expects($this->once())->method('getPostcode')->willReturn('78758'); - $this->billingAddress->expects($this->once())->method('getTelephone')->willReturn('512-1234567'); - $this->billingAddress->expects($this->once())->method('getRegionId')->willReturn(12); - $this->billingAddress->expects($this->once())->method('getCountryId')->willReturn('US'); $this->addressInformation->expects($this->once()) ->method('getShippingAddress') ->willReturn($this->shippingAddress); @@ -163,7 +150,7 @@ public function testBeforeSaveAddressInformationPickupStoreCompleteBilling(): vo } /** - * Test beforeSaveAddressInformation when pickup store shipping is false + * Test beforeSaveAddressInformation when it's not pickup store and billing is null * * @return void */ @@ -181,8 +168,10 @@ public function testBeforeSaveAddressInformationNotPickupStore(): void ->willReturn($this->shippingAddress); $this->addressInformation->expects($this->once()) ->method('getBillingAddress') - ->willReturn($this->billingAddress); - $this->addressInformation->expects($this->never())->method('setBillingAddress'); + ->willReturn(null); + $this->addressInformation->expects($this->once()) + ->method('setBillingAddress') + ->with($this->shippingAddress); $result = $this->plugin->beforeSaveAddressInformation( $this->subject, $cartId, From d335650632f012a0037a41214d719f40052c79e4 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Mon, 13 Oct 2025 14:43:08 +0300 Subject: [PATCH 41/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- ...ckInStoreGuestCustomerFillBillingAddressActionGroup.xml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml index 4d37364168b..d15bce99698 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml @@ -12,10 +12,13 @@ <description>Fill guest customer billing address for store pickup shipping method.</description> </annotations> <arguments> - <argument name="customerVar"/> - <argument name="customerAddressVar"/> + <argument name="customerVar" defaultValue="CustomerEntityOne"/> + <argument name="customerAddressVar" defaultValue="CustomerAddressSimple"/> </arguments> + <comment userInput="BIC workaround" stepKey="waitForEmailField"/> + <comment userInput="BIC workaround" stepKey="enterEmail"/> + <!-- The billing form is already in edit mode, so just wait for it to be visible --> <waitForElementVisible selector="{{CheckoutPaymentSection.guestFirstName}}" stepKey="waitForBillingFormVisible"/> From 70e479ef53e6aea4c08155a0329bc55b8e42b638 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Mon, 13 Oct 2025 15:32:39 +0300 Subject: [PATCH 42/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- ...ustomerForPickupOrderBundleProductTest.xml | 2 +- ...rForPickupOrderConfigurableProductTest.xml | 2 +- ...stomerForPickupOrderGroupedProductTest.xml | 2 +- ...tCustomerFillBillingAddressActionGroup.xml | 25 ++----------- ...illBillingAddressWithParamsActionGroup.xml | 35 +++++++++++++++++++ ...pleProductCustomStockCustomWebsiteTest.xml | 2 +- 6 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml index b9d0ab73e78..b07be99f041 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml @@ -114,7 +114,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> <argument name="customerVar" value="Simple_US_Customer"/> <argument name="customerAddressVar" value="US_Address_TX"/> </actionGroup> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml index b8774508aa2..ad269c51a58 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml @@ -114,7 +114,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> <argument name="customerVar" value="Simple_US_Customer"/> <argument name="customerAddressVar" value="US_Address_TX"/> </actionGroup> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml index 654aa21c8d3..97ddbe1407a 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml @@ -115,7 +115,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> <argument name="customerVar" value="Simple_US_Customer"/> <argument name="customerAddressVar" value="US_Address_TX"/> </actionGroup> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml index d15bce99698..c58f25e1490 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup.xml @@ -7,31 +7,12 @@ --> <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> - <actionGroup name="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup"> + <actionGroup name="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" extends="GuestCheckoutFillNewBillingAddressActionGroup"> <annotations> <description>Fill guest customer billing address for store pickup shipping method.</description> </annotations> - <arguments> - <argument name="customerVar" defaultValue="CustomerEntityOne"/> - <argument name="customerAddressVar" defaultValue="CustomerAddressSimple"/> - </arguments> - - <comment userInput="BIC workaround" stepKey="waitForEmailField"/> - <comment userInput="BIC workaround" stepKey="enterEmail"/> - - <!-- The billing form is already in edit mode, so just wait for it to be visible --> - <waitForElementVisible selector="{{CheckoutPaymentSection.guestFirstName}}" stepKey="waitForBillingFormVisible"/> - - <!-- Fill the form fields --> - <fillField selector="{{CheckoutPaymentSection.guestFirstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> - <fillField selector="{{CheckoutPaymentSection.guestLastName}}" userInput="{{customerVar.lastname}}" stepKey="enterLastName"/> - <fillField selector="{{CheckoutPaymentSection.guestStreet}}" userInput="{{customerAddressVar.street[0]}}" stepKey="enterStreet"/> - <fillField selector="{{CheckoutPaymentSection.guestCity}}" userInput="{{customerAddressVar.city}}" stepKey="enterCity"/> - <selectOption selector="{{CheckoutPaymentSection.guestRegion}}" userInput="{{customerAddressVar.state}}" stepKey="selectRegion"/> - <fillField selector="{{CheckoutPaymentSection.guestPostcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> - <fillField selector="{{CheckoutPaymentSection.guestTelephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> - - <!-- Save the address --> + <remove keyForRemoval="waitForEmailField"/> + <remove keyForRemoval="enterEmail"/> <click selector="{{CheckoutPaymentSection.update}}" stepKey="updateAddress"/> <waitForLoadingMaskToDisappear stepKey="waitForAddressUpdate"/> </actionGroup> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml new file mode 100644 index 00000000000..bbd894fc812 --- /dev/null +++ b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup"> + <annotations> + <description>Fill guest customer billing address for store pickup shipping method.</description> + </annotations> + <arguments> + <argument name="customerVar"/> + <argument name="customerAddressVar"/> + </arguments> + + <!-- The billing form is already in edit mode, so just wait for it to be visible --> + <waitForElementVisible selector="{{CheckoutPaymentSection.guestFirstName}}" stepKey="waitForBillingFormVisible"/> + + <!-- Fill the form fields --> + <fillField selector="{{CheckoutPaymentSection.guestFirstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutPaymentSection.guestLastName}}" userInput="{{customerVar.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutPaymentSection.guestStreet}}" userInput="{{customerAddressVar.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutPaymentSection.guestCity}}" userInput="{{customerAddressVar.city}}" stepKey="enterCity"/> + <selectOption selector="{{CheckoutPaymentSection.guestRegion}}" userInput="{{customerAddressVar.state}}" stepKey="selectRegion"/> + <fillField selector="{{CheckoutPaymentSection.guestPostcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> + <fillField selector="{{CheckoutPaymentSection.guestTelephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> + + <!-- Save the address --> + <click selector="{{CheckoutPaymentSection.update}}" stepKey="updateAddress"/> + <waitForLoadingMaskToDisappear stepKey="waitForAddressUpdate"/> + </actionGroup> +</actionGroups> diff --git a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml index 1c983db04a7..21f0091eef4 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/Test/StorefrontLoggedInCustomerCreateOrderWithSimpleProductCustomStockCustomWebsiteTest.xml @@ -132,7 +132,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressActionGroup" stepKey="fillAddress"> + <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> <argument name="customerVar" value="Simple_US_Customer"/> <argument name="customerAddressVar" value="US_Address_TX"/> </actionGroup> From 79aaf6eb2cfd8c50e5e9803fe81988b5fac65823 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Mon, 13 Oct 2025 15:35:02 +0300 Subject: [PATCH 43/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- ...toreGuestCustomerFillBillingAddressWithParamsActionGroup.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml index bbd894fc812..5a978e28eac 100644 --- a/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml +++ b/InventoryInStorePickupFrontend/Test/Mftf/ActionGroup/StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml @@ -9,7 +9,7 @@ <actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> <actionGroup name="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup"> <annotations> - <description>Fill guest customer billing address for store pickup shipping method.</description> + <description>Fill guest customer billing address for store pickup shipping method with provided address.</description> </annotations> <arguments> <argument name="customerVar"/> From e1c9e4c6a011aec61aaf09ec6a056b041e134e80 Mon Sep 17 00:00:00 2001 From: Alexandra Zota <zota@adobe.com> Date: Mon, 13 Oct 2025 17:59:35 +0300 Subject: [PATCH 44/46] ACP2E-4260: [MSI] Failing MFTF tests related to latest mainline changes. --- ...illBillingAddressWithParamsActionGroup.xml | 36 +++++++++++++++++++ ...ustomerForPickupOrderBundleProductTest.xml | 2 +- ...rForPickupOrderConfigurableProductTest.xml | 2 +- ...stomerForPickupOrderGroupedProductTest.xml | 2 +- 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 InventoryInStorePickupAdminUi/Test/Mftf/ActionGroup/AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/ActionGroup/AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml b/InventoryInStorePickupAdminUi/Test/Mftf/ActionGroup/AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml new file mode 100644 index 00000000000..fa57b6264e4 --- /dev/null +++ b/InventoryInStorePickupAdminUi/Test/Mftf/ActionGroup/AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright 2025 Adobe + * All Rights Reserved. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup"> + <annotations> + <description>Fill guest customer billing address for store pickup shipping method with provided address in admin.</description> + </annotations> + <arguments> + <argument name="customerVar"/> + <argument name="customerAddressVar"/> + </arguments> + + <!-- The billing form is already in edit mode, so just wait for it to be visible --> + <waitForElementVisible selector="{{CheckoutPaymentSection.guestFirstName}}" stepKey="waitForBillingFormVisible"/> + + <!-- Fill the form fields --> + <fillField selector="{{CheckoutPaymentSection.guestFirstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutPaymentSection.guestLastName}}" userInput="{{customerVar.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutPaymentSection.guestStreet}}" userInput="{{customerAddressVar.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutPaymentSection.guestCity}}" userInput="{{customerAddressVar.city}}" stepKey="enterCity"/> + <selectOption selector="{{CheckoutPaymentSection.guestRegion}}" userInput="{{customerAddressVar.state}}" stepKey="selectRegion"/> + <fillField selector="{{CheckoutPaymentSection.guestPostcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> + <fillField selector="{{CheckoutPaymentSection.guestTelephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> + + <!-- Save the address --> + <click selector="{{CheckoutPaymentSection.update}}" stepKey="updateAddress"/> + <waitForLoadingMaskToDisappear stepKey="waitForAddressUpdate"/> + </actionGroup> +</actionGroups> + diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml index b07be99f041..69c92246796 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderBundleProductTest.xml @@ -114,7 +114,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> + <actionGroup ref="AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> <argument name="customerVar" value="Simple_US_Customer"/> <argument name="customerAddressVar" value="US_Address_TX"/> </actionGroup> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml index ad269c51a58..8c31fdf01e7 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderConfigurableProductTest.xml @@ -114,7 +114,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> + <actionGroup ref="AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> <argument name="customerVar" value="Simple_US_Customer"/> <argument name="customerAddressVar" value="US_Address_TX"/> </actionGroup> diff --git a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml index 97ddbe1407a..8348cbdfd63 100644 --- a/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml +++ b/InventoryInStorePickupAdminUi/Test/Mftf/Test/AdminNotifyCustomerForPickupOrderGroupedProductTest.xml @@ -115,7 +115,7 @@ <argument name="sourceName" value="$culverSource.source[name]$"/> </actionGroup> <actionGroup ref="StorefrontPickInStoreNavigateToPaymentActionGroup" stepKey="navigateToPaymentStep"/> - <actionGroup ref="StorefrontPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> + <actionGroup ref="AdminPickInStoreGuestCustomerFillBillingAddressWithParamsActionGroup" stepKey="fillAddress"> <argument name="customerVar" value="Simple_US_Customer"/> <argument name="customerAddressVar" value="US_Address_TX"/> </actionGroup> From 48978051bb59adcae1203e782962b92851748de5 Mon Sep 17 00:00:00 2001 From: arnsaha <arnsaha@adobe.com> Date: Tue, 14 Oct 2025 13:01:19 -0500 Subject: [PATCH 45/46] ACP2E-4267: Incorrect inventory reservation created for virtual gift cards - Initial commit --- .../Result/GetDefaultSortedSourcesResult.php | 2 +- .../GetDefaultSortedSourcesResultTest.php | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/InventorySourceSelectionApi/Model/Algorithms/Result/GetDefaultSortedSourcesResult.php b/InventorySourceSelectionApi/Model/Algorithms/Result/GetDefaultSortedSourcesResult.php index f723443e82a..018ab245e39 100644 --- a/InventorySourceSelectionApi/Model/Algorithms/Result/GetDefaultSortedSourcesResult.php +++ b/InventorySourceSelectionApi/Model/Algorithms/Result/GetDefaultSortedSourcesResult.php @@ -96,7 +96,7 @@ public function execute( $itemsTdDeliver = []; foreach ($inventoryRequest->getItems() as $item) { $normalizedSku = $this->normalizeSku(trim($item->getSku())); - $itemsTdDeliver[$normalizedSku] = $item->getQty(); + $itemsTdDeliver[$normalizedSku] = ($itemsTdDeliver[$normalizedSku] ?? 0) + $item->getQty(); } $sortedSourceCodes = []; diff --git a/InventorySourceSelectionApi/Test/Integration/GetDefaultSortedSourcesResultTest.php b/InventorySourceSelectionApi/Test/Integration/GetDefaultSortedSourcesResultTest.php index d837b2ecc82..4c47fbd6111 100644 --- a/InventorySourceSelectionApi/Test/Integration/GetDefaultSortedSourcesResultTest.php +++ b/InventorySourceSelectionApi/Test/Integration/GetDefaultSortedSourcesResultTest.php @@ -132,6 +132,19 @@ public static function shouldReturnDefaultResultsDataProvider(): array ], true ], + [ + 20, + [ + ['sku' => 'SKU-2', 'qty' => 1], ['sku' => 'SKU-2', 'qty' => 2], + ], + [ + 'us-1', + ], + [ + 'us-1/SKU-2' => ['deduct' => 3, 'avail' => 5], + ], + true + ], ]; } From 4b1362b18d241c9daf9f962dd4e0df6bc544079e Mon Sep 17 00:00:00 2001 From: Karishma Thakare <del57145@adobe.com> Date: Fri, 17 Oct 2025 17:25:20 +0530 Subject: [PATCH 46/46] ACQE-8902: Mainline Deployment PR - Resolved conflicts --- ...cheValidationConfigurableProductSoldOutCustomStocksTest.xml | 3 ++- ...thConfigurableProductWithSwatchAttributeViaTheAdminTest.xml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml index 8132f854dd8..614f14eff22 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminCacheValidationConfigurableProductSoldOutCustomStocksTest.xml @@ -48,8 +48,9 @@ <!--Delete category, product and stock.--> <deleteData createDataKey="customer" stepKey="deleteCustomer"/> <deleteData createDataKey="category" stepKey="deleteCategory"/> - <deleteData createDataKey="configurableProduct" stepKey="deleteConfigurable"/> <deleteData createDataKey="additionalStockMainWebsite" stepKey="deleteMainWebsiteStock"/> + <!-- Delete all products via API --> + <helper class="Magento\Catalog\Test\Mftf\Helper\ProductApiHelper" method="deleteAllProductsApi" stepKey="deleteAllProductsViaApi"/> <actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex"> <argument name="indices" value=""/> </actionGroup> diff --git a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml index dc54bf56247..27b4eafec12 100644 --- a/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml +++ b/InventoryAdminUi/Test/Mftf/Test/AdminOrderCreatedForGuestCustomerWithConfigurableProductWithSwatchAttributeViaTheAdminTest.xml @@ -57,6 +57,8 @@ <actionGroup ref="AdminDeleteCustomerActionGroup" stepKey="deleteCustomerFromGrid"> <argument name="customerEmail" value="MsiCustomer1.email"/> </actionGroup> + <!-- Delete all products via API --> + <helper class="Magento\Catalog\Test\Mftf\Helper\ProductApiHelper" method="deleteAllProductsApi" stepKey="deleteAllProductsViaApi"/> <actionGroup ref="AdminLogoutActionGroup" stepKey="logoutOfAdmin1"/> <deleteData createDataKey="simpleCategory1" stepKey="deleteCategory1"/> </after>