diff --git a/vendor/magento/module-inventory-catalog/etc/di.xml b/vendor/magento/module-inventory-catalog/etc/di.xml
index d37e686786f..bb4272e6ffe 100644
--- a/vendor/magento/module-inventory-catalog/etc/di.xml
+++ b/vendor/magento/module-inventory-catalog/etc/di.xml
@@ -164,4 +164,8 @@
+
+
+
diff --git a/vendor/magento/module-inventory-indexer/etc/di.xml b/vendor/magento/module-inventory-indexer/etc/di.xml
index dd794617683..ac3f89ebcb8 100644
--- a/vendor/magento/module-inventory-indexer/etc/di.xml
+++ b/vendor/magento/module-inventory-indexer/etc/di.xml
@@ -39,6 +39,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 @@ declare(strict_types=1);
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 @@ class SourceDeductionService implements SourceDeductionServiceInterface
*/
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 @@ class SourceDeductionService implements SourceDeductionServiceInterface
$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 @@ class SourceDeductionService implements SourceDeductionServiceInterface
}
}
- if (!empty($sourceItems)) {
- $this->sourceItemsSave->execute($sourceItems);
+ if (!empty($sourceItemDecrementData)) {
+ $this->decrementSourceItem->execute($sourceItemDecrementData);
}
}
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..19d75d30b8d
--- /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..bc6914761f1
--- /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..5dd6035affc
--- /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..56adb3348fa
--- /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-indexer/Plugin/InventoryApi/ReindexAfterDecrementSourceItemQty.php b/vendor/magento/module-inventory-indexer/Plugin/InventoryApi/ReindexAfterDecrementSourceItemQty.php
new file mode 100644
index 00000000000..091af90d2cb
--- /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);
+ }
+ }
+}