diff --git a/app/code/Magento/InventorySales/Model/DeleteSalesChannelToStockLinkInterface.php b/app/code/Magento/InventorySales/Model/DeleteSalesChannelToStockLinkInterface.php new file mode 100644 index 000000000000..e37fde06b485 --- /dev/null +++ b/app/code/Magento/InventorySales/Model/DeleteSalesChannelToStockLinkInterface.php @@ -0,0 +1,23 @@ +resourceConnection = $resourceConnection; + } + + /** + * @inheritdoc + */ + public function execute(string $type, string $code) + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName(CreateSalesChannelTable::TABLE_NAME_SALES_CHANNEL); + + $connection->delete($tableName, [ + SalesChannelInterface::TYPE . ' = ?' => $type, + SalesChannelInterface::CODE . ' = ?' => $code, + ]); + } +} diff --git a/app/code/Magento/InventorySales/Model/ResourceModel/GetAssignedStockIdForWebsite.php b/app/code/Magento/InventorySales/Model/ResourceModel/GetAssignedStockIdForWebsite.php new file mode 100644 index 000000000000..d82a2da57ca1 --- /dev/null +++ b/app/code/Magento/InventorySales/Model/ResourceModel/GetAssignedStockIdForWebsite.php @@ -0,0 +1,54 @@ +resourceConnection = $resourceConnection; + } + + /** + * @inheritdoc + */ + public function execute(string $websiteCode) + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName(CreateSalesChannelTable::TABLE_NAME_SALES_CHANNEL); + + $select = $connection->select() + ->from($tableName, [CreateSalesChannelTable::STOCK_ID]) + ->where('code = ?', $websiteCode) + ->where('type = ?', SalesChannelInterface::TYPE_WEBSITE); + + $result = $connection->fetchCol($select); + + if (count($result) === 0) { + return null; + } + return reset($result); + } +} diff --git a/app/code/Magento/InventorySales/Model/ResourceModel/ReplaceSalesChannelsDataForStock.php b/app/code/Magento/InventorySales/Model/ResourceModel/ReplaceSalesChannelsDataForStock.php index 567f53ad4a7d..1f967aa4e5b8 100644 --- a/app/code/Magento/InventorySales/Model/ResourceModel/ReplaceSalesChannelsDataForStock.php +++ b/app/code/Magento/InventorySales/Model/ResourceModel/ReplaceSalesChannelsDataForStock.php @@ -35,11 +35,7 @@ public function __construct( } /** - * Replace Sales Channels for Stock - * - * @param SalesChannelInterface[] $salesChannels - * @param int $stockId - * @return void + * @inheritdoc */ public function execute(array $salesChannels, int $stockId) { diff --git a/app/code/Magento/InventorySales/Observer/Stock/PopulateWithWebsiteSalesChannelsObserver.php b/app/code/Magento/InventorySales/Observer/Stock/PopulateWithWebsiteSalesChannelsObserver.php index eb1242c9c0ea..3c73452baf11 100644 --- a/app/code/Magento/InventorySales/Observer/Stock/PopulateWithWebsiteSalesChannelsObserver.php +++ b/app/code/Magento/InventorySales/Observer/Stock/PopulateWithWebsiteSalesChannelsObserver.php @@ -49,9 +49,11 @@ public function execute(EventObserver $observer) $extensionAttributes = $stock->getExtensionAttributes(); $assignedSalesChannels = $extensionAttributes->getSalesChannels(); - foreach ($assignedSalesChannels as $key => $assignedSalesChannel) { - if ($assignedSalesChannel->getType() === SalesChannelInterface::TYPE_WEBSITE) { - unset($assignedSalesChannels[$key]); + if (null !== $assignedSalesChannels) { + foreach ($assignedSalesChannels as $key => $assignedSalesChannel) { + if ($assignedSalesChannel->getType() === SalesChannelInterface::TYPE_WEBSITE) { + unset($assignedSalesChannels[$key]); + } } } diff --git a/app/code/Magento/InventorySales/Observer/Website/AssignWebsiteToDefaultStock.php b/app/code/Magento/InventorySales/Observer/Website/AssignWebsiteToDefaultStock.php new file mode 100644 index 000000000000..d913649f5739 --- /dev/null +++ b/app/code/Magento/InventorySales/Observer/Website/AssignWebsiteToDefaultStock.php @@ -0,0 +1,105 @@ +stockRepository = $stockRepository; + $this->defaultStockProvider = $defaultStockProvider; + $this->salesChannelFactory = $salesChannelFactory; + $this->getAssignedStockIdForWebsite = $getAssignedStockIdForWebsite; + } + + /** + * @inheritdoc + */ + public function execute(Observer $observer) + { + /** @var Website $website */ + $website = $observer->getData('website'); + $websiteCode = $website->getCode(); + + if ($websiteCode === WebsiteInterface::ADMIN_CODE) { + return; + } + + // checks is some stock already assigned to this website + if ($this->getAssignedStockIdForWebsite->execute($websiteCode) !== null) { + return; + } + + $defaultStockId = $this->defaultStockProvider->getId(); + $defaultStock = $this->stockRepository->get($defaultStockId); + + $extensionAttributes = $defaultStock->getExtensionAttributes(); + $salesChannels = $extensionAttributes->getSalesChannels(); + $salesChannels[] = $this->createSalesChannelByWebsiteCode($websiteCode); + + $extensionAttributes->setSalesChannels($salesChannels); + $this->stockRepository->save($defaultStock); + } + + /** + * Create the sales channel by given website code + * + * @param string $websiteCode + * @return SalesChannelInterface + */ + private function createSalesChannelByWebsiteCode(string $websiteCode): SalesChannelInterface + { + $salesChannel = $this->salesChannelFactory->create(); + $salesChannel->setCode($websiteCode); + $salesChannel->setType(SalesChannelInterface::TYPE_WEBSITE); + return $salesChannel; + } +} diff --git a/app/code/Magento/InventorySales/Observer/Website/DeleteWebsiteToStockLink.php b/app/code/Magento/InventorySales/Observer/Website/DeleteWebsiteToStockLink.php new file mode 100644 index 000000000000..47e182a1feae --- /dev/null +++ b/app/code/Magento/InventorySales/Observer/Website/DeleteWebsiteToStockLink.php @@ -0,0 +1,50 @@ +deleteSalesChannelToStockLink = $deleteSalesChannelToStockLink; + } + + /** + * @inheritdoc + */ + public function execute(Observer $observer) + { + /** @var Website $website */ + $website = $observer->getData('website'); + $websiteCode = $website->getCode(); + + if ($websiteCode === WebsiteInterface::ADMIN_CODE) { + return; + } + $this->deleteSalesChannelToStockLink->execute(SalesChannelInterface::TYPE_WEBSITE, $websiteCode); + } +} diff --git a/app/code/Magento/InventorySales/Test/Integration/Website/AssignWebsiteToDefaultStockTest.php b/app/code/Magento/InventorySales/Test/Integration/Website/AssignWebsiteToDefaultStockTest.php new file mode 100644 index 000000000000..b9fd61ea6c08 --- /dev/null +++ b/app/code/Magento/InventorySales/Test/Integration/Website/AssignWebsiteToDefaultStockTest.php @@ -0,0 +1,68 @@ +websiteFactory = Bootstrap::getObjectManager()->get(WebsiteFactory::class); + $this->stockRepository = Bootstrap::getObjectManager()->get(StockRepositoryInterface::class); + $this->defaultStockProvider = Bootstrap::getObjectManager()->get(DefaultStockProviderInterface::class); + } + + /** + * Creates website inside of test so need to enable db isolation to prevent change db state after test execution + * @magentoDbIsolation enabled + */ + public function testCreateWebsiteIfSalesChannelsAreEmpty() + { + $websiteCode = 'test_1'; + + /** @var Website $website */ + $website = $this->websiteFactory->create(); + $website->setCode($websiteCode); + // Use website model because we haven't api interfaces for website saving + $website->save(); + + $defaultStockId = $this->defaultStockProvider->getId(); + $defaultStock = $this->stockRepository->get($defaultStockId); + + $extensionAttributes = $defaultStock->getExtensionAttributes(); + $salesChannels = $extensionAttributes->getSalesChannels(); + self::assertContainsOnlyInstancesOf(SalesChannelInterface::class, $salesChannels); + self::assertCount(1, $salesChannels); + + $salesChannel = reset($salesChannels); + self::assertEquals($website->getCode(), $salesChannel->getCode()); + self::assertEquals(SalesChannelInterface::TYPE_WEBSITE, $salesChannel->getType()); + } +} diff --git a/app/code/Magento/InventorySales/Test/Integration/Website/DeleteWebsiteToStockLinkTest.php b/app/code/Magento/InventorySales/Test/Integration/Website/DeleteWebsiteToStockLinkTest.php new file mode 100644 index 000000000000..05d45ba35962 --- /dev/null +++ b/app/code/Magento/InventorySales/Test/Integration/Website/DeleteWebsiteToStockLinkTest.php @@ -0,0 +1,69 @@ +websiteFactory = Bootstrap::getObjectManager()->get(WebsiteFactory::class); + $this->getAssignedStockIdForWebsite = Bootstrap::getObjectManager()->get( + GetAssignedStockIdForWebsiteInterface::class + ); + } + + /** + * Creates website inside of test so need to enable db isolation to prevent change db state after test execution + * @magentoDbIsolation enabled + */ + public function testGetAssignedStocksForWebsite() + { + $websiteCode = 'test_1'; + + /** @var Website $website */ + $website = $this->websiteFactory->create(); + $website->setCode($websiteCode); + // Use website model because we haven't api interfaces for website saving/deleting + $website->save(); + $this->deleteWebsite($website); + + $stockId = $this->getAssignedStockIdForWebsite->execute($websiteCode); + self::assertNull($stockId); + } + + /** + * @param Website $website + * @return void + */ + private function deleteWebsite(Website $website) + { + $registry = Bootstrap::getObjectManager()->get(Registry::class); + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', true); + $website->delete(); + $registry->unregister('isSecureArea'); + $registry->register('isSecureArea', false); + } +} diff --git a/app/code/Magento/InventorySales/Test/Integration/Website/GetAssignedStockIdForWebsiteTest.php b/app/code/Magento/InventorySales/Test/Integration/Website/GetAssignedStockIdForWebsiteTest.php new file mode 100644 index 000000000000..288aa04566ba --- /dev/null +++ b/app/code/Magento/InventorySales/Test/Integration/Website/GetAssignedStockIdForWebsiteTest.php @@ -0,0 +1,65 @@ +websiteFactory = Bootstrap::getObjectManager()->get(WebsiteFactory::class); + $this->getAssignedStockIdForWebsite = Bootstrap::getObjectManager()->get( + GetAssignedStockIdForWebsiteInterface::class + ); + $this->defaultStockProvider = Bootstrap::getObjectManager()->get(DefaultStockProviderInterface::class); + } + + public function testGetAssignedStocksForNotExistedWebsite() + { + self::assertNull($this->getAssignedStockIdForWebsite->execute('not_existed_website_code')); + } + + /** + * Creates website inside of test so need to enable db isolation to prevent change db state after test execution + * @magentoDbIsolation enabled + */ + public function testGetAssignedStocksForWebsite() + { + $websiteCode = 'test_1'; + + /** @var Website $website */ + $website = $this->websiteFactory->create(); + $website->setCode($websiteCode); + // Use website model because we haven't api interfaces for website saving + $website->save(); + + $stockId = $this->getAssignedStockIdForWebsite->execute($websiteCode); + self::assertEquals($this->defaultStockProvider->getId(), $stockId); + } +} diff --git a/app/code/Magento/InventorySales/etc/di.xml b/app/code/Magento/InventorySales/etc/di.xml index 87feda242e6c..5d4c7be74aaf 100644 --- a/app/code/Magento/InventorySales/etc/di.xml +++ b/app/code/Magento/InventorySales/etc/di.xml @@ -11,6 +11,8 @@ + + diff --git a/app/code/Magento/InventorySales/etc/events.xml b/app/code/Magento/InventorySales/etc/events.xml new file mode 100644 index 000000000000..214d97feeb2d --- /dev/null +++ b/app/code/Magento/InventorySales/etc/events.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/website_attribute_sync_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/website_attribute_sync_rollback.php index 7505e3430d53..307dbede649e 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/website_attribute_sync_rollback.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/ResourceModel/_files/website_attribute_sync_rollback.php @@ -76,12 +76,10 @@ /** * remove website by id */ -$connection->delete( - $resourceConnection->getTableName('store_website'), - [ - 'website_id = ?' => $websiteId, - ] -); +/** @var \Magento\Store\Model\Website $website */ +$website = Bootstrap::getObjectManager()->create(\Magento\Store\Model\Website::class); +$website->load((int)$websiteId); +$website->delete(); /** * reIndex all