diff --git a/vendor/magento/module-inventory/Model/ResourceModel/SourceItem/DecrementQtyForMultipleSourceItem.php b/vendor/magento/module-inventory/Model/ResourceModel/SourceItem/DecrementQtyForMultipleSourceItem.php new file mode 100644 index 00000000000..72cc72e4aed --- /dev/null +++ b/vendor/magento/module-inventory/Model/ResourceModel/SourceItem/DecrementQtyForMultipleSourceItem.php @@ -0,0 +1,58 @@ +resourceConnection = $resourceConnection; + } + + /** + * Decrement qty for source item + * + * @param array $decrementItems + * @return void + */ + public function execute(array $decrementItems): void + { + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName(SourceItemResourceModel::TABLE_NAME_SOURCE_ITEM); + if (!count($decrementItems)) { + return; + } + foreach ($decrementItems as $decrementItem) { + $sourceItem = $decrementItem['source_item']; + $where = [ + 'source_code = ?' => $sourceItem->getSourceCode(), + 'sku = ?' => $sourceItem->getSku() + ]; + $connection->update( + [$tableName], + ['quantity' => new \Zend_Db_Expr('quantity - ' . $decrementItem['qty_to_decrement'])], + $where + ); + } + } +} diff --git a/vendor/magento/module-inventory/Model/SourceItem/Command/DecrementSourceItemQty.php b/vendor/magento/module-inventory/Model/SourceItem/Command/DecrementSourceItemQty.php new file mode 100644 index 00000000000..6bf67bfc658 --- /dev/null +++ b/vendor/magento/module-inventory/Model/SourceItem/Command/DecrementSourceItemQty.php @@ -0,0 +1,93 @@ +sourceItemsValidator = $sourceItemsValidator; + $this->decrementSourceItem = $decrementSourceItem; + $this->logger = $logger; + } + + /** + * Decrement quantity for Multiple Source + * + * @param array $sourceItemDecrementData + * @return void + * @throws InputException + * @throws ValidationException + * @throws CouldNotSaveException + */ + public function execute(array $sourceItemDecrementData): void + { + $this->validateSourceItems($sourceItemDecrementData); + try { + $this->decrementSourceItem->execute($sourceItemDecrementData); + } catch (Exception $e) { + $this->logger->error($e->getMessage()); + throw new CouldNotSaveException(__('Could not save Source Item'), $e); + } + } + + /** + * Validate source items data + * + * @param array $sourceItemDecrementData + * @return void + * @throws InputException + * @throws ValidationException + */ + private function validateSourceItems(array $sourceItemDecrementData): void + { + $sourceItems = array_column($sourceItemDecrementData, 'source_item'); + if (empty($sourceItems)) { + throw new InputException(__('Input data is empty')); + } + $validationResult = $this->sourceItemsValidator->validate($sourceItems); + if (!$validationResult->isValid()) { + $error = current($validationResult->getErrors()); + throw new ValidationException(__('Validation Failed: ' . $error), null, 0, $validationResult); + } + } +} diff --git a/vendor/magento/module-inventory-catalog/Model/ResourceModel/DecrementQtyForLegacyStock.php b/vendor/magento/module-inventory-catalog/Model/ResourceModel/DecrementQtyForLegacyStock.php new file mode 100644 index 00000000000..cde36f12c73 --- /dev/null +++ b/vendor/magento/module-inventory-catalog/Model/ResourceModel/DecrementQtyForLegacyStock.php @@ -0,0 +1,93 @@ +defaultSourceProvider = $defaultSourceProvider; + $this->getProductIdsBySkus = $getProductIdsBySkus; + $this->resourceConnection = $resourceConnection; + } + + /** + * Decrement quantity for legacy stock after decrements quantity of msi stock + * + * @param array $decrementItems + * @return void + */ + public function execute(array $decrementItems): void + { + if (!count($decrementItems)) { + return; + } + $connection = $this->resourceConnection->getConnection(); + $tableName = $this->resourceConnection->getTableName('cataloginventory_stock_item'); + foreach ($decrementItems as $decrementItem) { + $sourceItem = $decrementItem['source_item']; + $status = (int)$sourceItem->getStatus(); + if ($sourceItem->getSourceCode() !== $this->defaultSourceProvider->getCode()) { + continue; + } + + $sku = $sourceItem->getSku(); + try { + $productId = (int)$this->getProductIdsBySkus->execute([$sku])[$sku]; + } catch (NoSuchEntityException $e) { + // Skip synchronization for not existed product + continue; + } + + $where = [ + StockItemInterface::PRODUCT_ID . ' = ?' => $productId, + 'website_id = ?' => 0 + ]; + $connection->update( + [$tableName], + [ + 'qty' => new \Zend_Db_Expr('qty - ' . $decrementItem['qty_to_decrement']), + 'is_in_stock' => $status + ], + $where + ); + } + } +} diff --git a/vendor/magento/module-inventory-catalog/Plugin/InventoryApi/SynchronizeLegacyStockAfterDecrementStockPlugin.php b/vendor/magento/module-inventory-catalog/Plugin/InventoryApi/SynchronizeLegacyStockAfterDecrementStockPlugin.php new file mode 100644 index 00000000000..67360c7ad89 --- /dev/null +++ b/vendor/magento/module-inventory-catalog/Plugin/InventoryApi/SynchronizeLegacyStockAfterDecrementStockPlugin.php @@ -0,0 +1,152 @@ +decrementQuantityForLegacyCatalogInventory = $decrementQuantityForLegacyCatalogInventory; + $this->getProductIdsBySkus = $getProductIdsBySkus; + $this->indexerProcessor = $indexerProcessor; + $this->setDataToLegacyStockStatus = $setDataToLegacyStockStatus; + $this->legacyStockItemCriteriaFactory = $legacyStockItemCriteriaFactory; + $this->legacyStockItemRepository = $legacyStockItemRepository; + $this->stockStateProvider = $stockStateProvider; + } + + /** + * @param DecrementSourceItemQty $subject + * @param void $result + * @param SourceItemInterface[] $sourceItemDecrementData + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterExecute(DecrementSourceItemQty $subject, $result, array $sourceItemDecrementData): void + { + $productIds = []; + $this->decrementQuantityForLegacyCatalogInventory->execute($sourceItemDecrementData); + $sourceItems = array_column($sourceItemDecrementData, 'source_item'); + foreach ($sourceItems as $sourceItem) { + $sku = $sourceItem->getSku(); + $productId = (int)$this->getProductIdsBySkus->execute([$sku])[$sku]; + $productIds[] = $productId; + + $legacyStockItem = $this->getLegacyStockItem($productId); + if (null === $legacyStockItem) { + continue; + } + $isInStock = (int)$sourceItem->getStatus(); + if ($legacyStockItem->getManageStock()) { + $legacyStockItem->setIsInStock($isInStock); + $legacyStockItem->setQty((float)$sourceItem->getQuantity()); + + if (false === $this->stockStateProvider->verifyStock($legacyStockItem)) { + $isInStock = 0; + } + } + $this->setDataToLegacyStockStatus->execute( + (string)$sourceItem->getSku(), + (float)$sourceItem->getQuantity(), + $isInStock + ); + } + if ($productIds) { + $this->indexerProcessor->reindexList($productIds); + } + } + + /** + * Returns StockItem from legacy inventory. + * + * @param int $productId + * @return null|StockItemInterface + */ + private function getLegacyStockItem(int $productId): ?StockItemInterface + { + $searchCriteria = $this->legacyStockItemCriteriaFactory->create(); + + $searchCriteria->addFilter(StockItemInterface::PRODUCT_ID, StockItemInterface::PRODUCT_ID, $productId); + $searchCriteria->addFilter(StockItemInterface::STOCK_ID, StockItemInterface::STOCK_ID, Stock::DEFAULT_STOCK_ID); + + $stockItemCollection = $this->legacyStockItemRepository->getList($searchCriteria); + if ($stockItemCollection->getTotalCount() === 0) { + return null; + } + + $stockItems = $stockItemCollection->getItems(); + $stockItem = reset($stockItems); + return $stockItem; + } +} diff --git a/vendor/magento/module-inventory-catalog/etc/di.xml b/vendor/magento/module-inventory-catalog/etc/di.xml index b0dff41f921..8890f51460a 100644 --- a/vendor/magento/module-inventory-catalog/etc/di.xml +++ b/vendor/magento/module-inventory-catalog/etc/di.xml @@ -21,6 +21,10 @@ + + + diff --git a/vendor/magento/module-inventory-indexer/Plugin/InventoryApi/ReindexAfterDecrementSourceItemQty.php b/vendor/magento/module-inventory-indexer/Plugin/InventoryApi/ReindexAfterDecrementSourceItemQty.php new file mode 100644 index 00000000000..ac536eb7974 --- /dev/null +++ b/vendor/magento/module-inventory-indexer/Plugin/InventoryApi/ReindexAfterDecrementSourceItemQty.php @@ -0,0 +1,58 @@ +getSourceItemIds = $getSourceItemIds; + $this->sourceItemIndexer = $sourceItemIndexer; + } + + /** + * @param DecrementSourceItemQty $subject + * @param void $result + * @param SourceItemInterface[] $sourceItems + * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterExecute( + DecrementSourceItemQty $subject, + $result, + array $sourceItemDecrementData + ) { + $sourceItems = array_column($sourceItemDecrementData, 'source_item'); + $sourceItemIds = $this->getSourceItemIds->execute($sourceItems); + if (count($sourceItemIds)) { + $this->sourceItemIndexer->executeList($sourceItemIds); + } + } +} diff --git a/vendor/magento/module-inventory-indexer/etc/di.xml b/vendor/magento/module-inventory-indexer/etc/di.xml index f6914e24ab7..2388d0105d6 100644 --- a/vendor/magento/module-inventory-indexer/etc/di.xml +++ b/vendor/magento/module-inventory-indexer/etc/di.xml @@ -55,6 +55,9 @@ + + + diff --git a/vendor/magento/module-inventory-source-deduction-api/Model/SourceDeductionService.php b/vendor/magento/module-inventory-source-deduction-api/Model/SourceDeductionService.php index 72f57475943..a815864095a 100644 --- a/vendor/magento/module-inventory-source-deduction-api/Model/SourceDeductionService.php +++ b/vendor/magento/module-inventory-source-deduction-api/Model/SourceDeductionService.php @@ -8,8 +8,8 @@ namespace Magento\InventorySourceDeductionApi\Model; use Magento\Framework\Exception\LocalizedException; +use Magento\Inventory\Model\SourceItem\Command\DecrementSourceItemQty; use Magento\InventoryApi\Api\Data\SourceItemInterface; -use Magento\InventoryApi\Api\SourceItemsSaveInterface; use Magento\InventoryConfigurationApi\Api\Data\StockItemConfigurationInterface; use Magento\InventoryConfigurationApi\Api\GetStockItemConfigurationInterface; use Magento\InventorySalesApi\Api\GetStockBySalesChannelInterface; @@ -24,11 +24,6 @@ class SourceDeductionService implements SourceDeductionServiceInterface */ private const ZERO_STOCK_QUANTITY = 0.0; - /** - * @var SourceItemsSaveInterface - */ - private $sourceItemsSave; - /** * @var GetSourceItemBySourceCodeAndSku */ @@ -45,21 +40,26 @@ class SourceDeductionService implements SourceDeductionServiceInterface private $getStockBySalesChannel; /** - * @param SourceItemsSaveInterface $sourceItemsSave + * @var DecrementSourceItemQty + */ + private $decrementSourceItem; + + /** * @param GetSourceItemBySourceCodeAndSku $getSourceItemBySourceCodeAndSku * @param GetStockItemConfigurationInterface $getStockItemConfiguration * @param GetStockBySalesChannelInterface $getStockBySalesChannel + * @param DecrementSourceItemQty $decrementSourceItem */ public function __construct( - SourceItemsSaveInterface $sourceItemsSave, GetSourceItemBySourceCodeAndSku $getSourceItemBySourceCodeAndSku, GetStockItemConfigurationInterface $getStockItemConfiguration, - GetStockBySalesChannelInterface $getStockBySalesChannel + GetStockBySalesChannelInterface $getStockBySalesChannel, + DecrementSourceItemQty $decrementSourceItem ) { - $this->sourceItemsSave = $sourceItemsSave; $this->getSourceItemBySourceCodeAndSku = $getSourceItemBySourceCodeAndSku; $this->getStockItemConfiguration = $getStockItemConfiguration; $this->getStockBySalesChannel = $getStockBySalesChannel; + $this->decrementSourceItem = $decrementSourceItem; } /** @@ -67,11 +67,10 @@ public function __construct( */ public function execute(SourceDeductionRequestInterface $sourceDeductionRequest): void { - $sourceItems = []; $sourceCode = $sourceDeductionRequest->getSourceCode(); $salesChannel = $sourceDeductionRequest->getSalesChannel(); - $stockId = $this->getStockBySalesChannel->execute($salesChannel)->getStockId(); + $sourceItemDecrementData = []; foreach ($sourceDeductionRequest->getItems() as $item) { $itemSku = $item->getSku(); $qty = $item->getQty(); @@ -93,7 +92,10 @@ public function execute(SourceDeductionRequestInterface $sourceDeductionRequest) $sourceItem ); $sourceItem->setStatus($stockStatus); - $sourceItems[] = $sourceItem; + $sourceItemDecrementData[] = [ + 'source_item' => $sourceItem, + 'qty_to_decrement' => $qty + ]; } else { throw new LocalizedException( __('Not all of your products are available in the requested quantity.') @@ -101,8 +103,8 @@ public function execute(SourceDeductionRequestInterface $sourceDeductionRequest) } } - if (!empty($sourceItems)) { - $this->sourceItemsSave->execute($sourceItems); + if (!empty($sourceItemDecrementData)) { + $this->decrementSourceItem->execute($sourceItemDecrementData); } }