diff --git a/vendor/magento/module-inventory-catalog/Model/BulkInventoryTransfer.php b/vendor/magento/module-inventory-catalog/Model/BulkInventoryTransfer.php
index 9aebf77319a0..8c07323039d8 100644
--- a/vendor/magento/module-inventory-catalog/Model/BulkInventoryTransfer.php
+++ b/vendor/magento/module-inventory-catalog/Model/BulkInventoryTransfer.php
@@ -10,6 +10,8 @@
use Magento\CatalogInventory\Model\Indexer\Stock as LegacyIndexer;
use Magento\Framework\Validation\ValidationException;
use Magento\InventoryCatalog\Model\ResourceModel\BulkInventoryTransfer as BulkInventoryTransferResource;
+use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockItem;
+use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockStatus;
use Magento\InventoryCatalogApi\Api\BulkInventoryTransferInterface;
use Magento\InventoryCatalogApi\Api\DefaultSourceProviderInterface;
use Magento\InventoryCatalogApi\Model\BulkInventoryTransferValidatorInterface;
@@ -51,6 +53,21 @@ class BulkInventoryTransfer implements BulkInventoryTransferInterface
*/
private $sourceIndexer;
+ /**
+ * @var GetSourceItemsBySkuAndSourceCodes
+ */
+ private $getSourceItemsBySkuAndSourceCodes;
+
+ /**
+ * @var SetDataToLegacyStockStatus
+ */
+ private $setDataToLegacyStockStatus;
+
+ /**
+ * @var SetDataToLegacyStockItem
+ */
+ private $setDataToLegacyStockItem;
+
/**
* @param BulkInventoryTransferValidatorInterface $inventoryTransferValidator
* @param BulkInventoryTransferResource $bulkInventoryTransfer
@@ -58,6 +75,9 @@ class BulkInventoryTransfer implements BulkInventoryTransferInterface
* @param DefaultSourceProviderInterface $defaultSourceProvider
* @param GetProductIdsBySkusInterface $getProductIdsBySkus
* @param LegacyIndexer $legacyIndexer
+ * @param GetSourceItemsBySkuAndSourceCodes $getSourceItemsBySkuAndSourceCodes
+ * @param SetDataToLegacyStockStatus $setDataToLegacyStockStatus
+ * @param SetDataToLegacyStockItem $setDataToLegacyStockItem
* @SuppressWarnings(PHPMD.LongVariable)
*/
public function __construct(
@@ -66,7 +86,10 @@ public function __construct(
SourceIndexer $sourceIndexer,
DefaultSourceProviderInterface $defaultSourceProvider,
GetProductIdsBySkusInterface $getProductIdsBySkus,
- LegacyIndexer $legacyIndexer
+ LegacyIndexer $legacyIndexer,
+ GetSourceItemsBySkuAndSourceCodes $getSourceItemsBySkuAndSourceCodes,
+ SetDataToLegacyStockStatus $setDataToLegacyStockStatus,
+ SetDataToLegacyStockItem $setDataToLegacyStockItem
) {
$this->bulkInventoryTransferValidator = $inventoryTransferValidator;
$this->bulkInventoryTransfer = $bulkInventoryTransfer;
@@ -74,6 +97,9 @@ public function __construct(
$this->legacyIndexer = $legacyIndexer;
$this->defaultSourceProvider = $defaultSourceProvider;
$this->sourceIndexer = $sourceIndexer;
+ $this->getSourceItemsBySkuAndSourceCodes = $getSourceItemsBySkuAndSourceCodes;
+ $this->setDataToLegacyStockStatus = $setDataToLegacyStockStatus;
+ $this->setDataToLegacyStockItem = $setDataToLegacyStockItem;
}
/**
@@ -111,6 +137,7 @@ public function execute(
if (($this->defaultSourceProvider->getCode() === $originSource) ||
($this->defaultSourceProvider->getCode() === $destinationSource)) {
+ $this->updateStockInfoForLegacyStock($skus);
$productIds = array_values($this->getProductIdsBySkus->execute($skus));
$this->reindexLegacy($productIds);
}
@@ -118,6 +145,34 @@ public function execute(
return true;
}
+ /**
+ * Update legacy stock status and stock item
+ *
+ * @param array $skus
+ * @return void
+ */
+ private function updateStockInfoForLegacyStock(array $skus): void
+ {
+ foreach ($skus as $sku) {
+ $sourceItems = $this->getSourceItemsBySkuAndSourceCodes->execute(
+ $sku,
+ [$this->defaultSourceProvider->getCode()]
+ );
+ foreach ($sourceItems as $sourceItem) {
+ $this->setDataToLegacyStockItem->execute(
+ (string)$sourceItem->getSku(),
+ (float)$sourceItem->getQuantity(),
+ (int)$sourceItem->getStatus()
+ );
+ $this->setDataToLegacyStockStatus->execute(
+ (string)$sourceItem->getSku(),
+ (float)$sourceItem->getQuantity(),
+ (int)$sourceItem->getStatus()
+ );
+ }
+ }
+ }
+
/**
* Reindex legacy stock (for default source).
*
diff --git a/vendor/magento/module-inventory-catalog/Model/ResourceModel/StockStatusExpressionForDefaultStock.php b/vendor/magento/module-inventory-catalog/Model/ResourceModel/StockStatusExpressionForDefaultStock.php
new file mode 100644
index 000000000000..1966ab83c210
--- /dev/null
+++ b/vendor/magento/module-inventory-catalog/Model/ResourceModel/StockStatusExpressionForDefaultStock.php
@@ -0,0 +1,67 @@
+scopeConfig = $scopeConfig;
+ }
+
+ /**
+ * Returns status expressions for MySQL query
+ *
+ * @ingeritdoc
+ * @param AdapterInterface $connection
+ * @param bool $isAggregate
+ * @return Zend_Db_Expr
+ */
+ public function getExpression(AdapterInterface $connection, bool $isAggregate): Zend_Db_Expr
+ {
+ $isManageStock = $this->scopeConfig->isSetFlag(
+ Configuration::XML_PATH_MANAGE_STOCK,
+ ScopeInterface::SCOPE_STORE
+ );
+ $stockItemInStockField = $isAggregate ? 'MAX(cisi.is_in_stock)' : 'cisi.is_in_stock';
+ $isInStockExpression = $connection->getCheckSql(
+ 'cisi.is_in_stock = 0',
+ 0,
+ $connection->getCheckSql('css.stock_status IS NOT NULL', 'css.stock_status', $stockItemInStockField)
+ );
+
+ if ($isManageStock) {
+ $statusExpr = $connection->getCheckSql(
+ 'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 0',
+ 1,
+ $isInStockExpression
+ );
+ } else {
+ $statusExpr = $connection->getCheckSql(
+ 'cisi.use_config_manage_stock = 0 AND cisi.manage_stock = 1',
+ $isInStockExpression,
+ 1
+ );
+ }
+ return $statusExpr;
+ }
+}
diff --git a/vendor/magento/module-inventory-catalog/Model/SourceItemsSaveSynchronization/SetDataToLegacyCatalogInventory.php b/vendor/magento/module-inventory-catalog/Model/SourceItemsSaveSynchronization/SetDataToLegacyCatalogInventory.php
index a2d267bc0be0..b4cd49e7bcc7 100644
--- a/vendor/magento/module-inventory-catalog/Model/SourceItemsSaveSynchronization/SetDataToLegacyCatalogInventory.php
+++ b/vendor/magento/module-inventory-catalog/Model/SourceItemsSaveSynchronization/SetDataToLegacyCatalogInventory.php
@@ -18,6 +18,7 @@
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockItem;
use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockStatus;
use Magento\InventoryCatalogApi\Model\SourceItemsSaveSynchronizationInterface;
+use Magento\InventorySalesApi\Api\AreProductsSalableInterface;
/**
* Set Qty and status for legacy CatalogInventory Stock Information tables.
@@ -59,6 +60,11 @@ class SetDataToLegacyCatalogInventory
*/
private $indexerProcessor;
+ /**
+ * @var AreProductsSalableInterface
+ */
+ private $areProductsSalable;
+
/**
* @param SetDataToLegacyStockItem $setDataToLegacyStockItem
* @param StockItemCriteriaInterfaceFactory $legacyStockItemCriteriaFactory
@@ -67,6 +73,7 @@ class SetDataToLegacyCatalogInventory
* @param StockStateProviderInterface $stockStateProvider
* @param Processor $indexerProcessor
* @param SetDataToLegacyStockStatus $setDataToLegacyStockStatus
+ * @param AreProductsSalableInterface $areProductsSalable
*/
public function __construct(
SetDataToLegacyStockItem $setDataToLegacyStockItem,
@@ -75,7 +82,8 @@ public function __construct(
GetProductIdsBySkusInterface $getProductIdsBySkus,
StockStateProviderInterface $stockStateProvider,
Processor $indexerProcessor,
- SetDataToLegacyStockStatus $setDataToLegacyStockStatus
+ SetDataToLegacyStockStatus $setDataToLegacyStockStatus,
+ AreProductsSalableInterface $areProductsSalable
) {
$this->setDataToLegacyStockItem = $setDataToLegacyStockItem;
$this->setDataToLegacyStockStatus = $setDataToLegacyStockStatus;
@@ -84,6 +92,7 @@ public function __construct(
$this->getProductIdsBySkus = $getProductIdsBySkus;
$this->stockStateProvider = $stockStateProvider;
$this->indexerProcessor = $indexerProcessor;
+ $this->areProductsSalable = $areProductsSalable;
}
/**
@@ -94,6 +103,12 @@ public function __construct(
*/
public function execute(array $sourceItems): void
{
+ $skus = [];
+ foreach ($sourceItems as $sourceItem) {
+ $skus[] = $sourceItem->getSku();
+ }
+
+ $stockStatuses = $this->getStockStatuses($skus);
$productIds = [];
foreach ($sourceItems as $sourceItem) {
$sku = $sourceItem->getSku();
@@ -129,7 +144,7 @@ public function execute(array $sourceItems): void
$this->setDataToLegacyStockStatus->execute(
(string)$sourceItem->getSku(),
(float)$sourceItem->getQuantity(),
- $isInStock
+ (int)$stockStatuses[(string)$sourceItem->getSku()]
);
$productIds[] = $productId;
}
@@ -139,6 +154,21 @@ public function execute(array $sourceItems): void
}
}
+ /**
+ * Returns items stock statuses.
+ *
+ * @param array $skus
+ * @return array
+ */
+ private function getStockStatuses(array $skus): array
+ {
+ $stockStatuses = [];
+ foreach ($this->areProductsSalable->execute($skus, Stock::DEFAULT_STOCK_ID) as $productSalable) {
+ $stockStatuses[$productSalable->getSku()] = $productSalable->isSalable();
+ }
+ return $stockStatuses;
+ }
+
/**
* Returns StockItem from legacy inventory.
*
diff --git a/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptUpdateStockStatusBySkuPlugin.php b/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptUpdateStockStatusBySkuPlugin.php
new file mode 100644
index 000000000000..afe66fea814b
--- /dev/null
+++ b/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Api/StockRegistry/AdaptUpdateStockStatusBySkuPlugin.php
@@ -0,0 +1,105 @@
+setDataToLegacyStockStatus = $setDataToLegacyStockStatus;
+ $this->getProductTypesBySkus = $getProductTypesBySkus;
+ $this->isSourceItemManagementAllowedForProductType = $isSourceItemManagementAllowedForProductType;
+ $this->getStockItemConfiguration = $getStockItemConfiguration;
+ $this->legacyStockItemCacheStorage = $legacyStockItemCacheStorage;
+ }
+
+ /**
+ * Replicate stock status information to legacy stock.
+ *
+ * @param StockRegistryInterface $subject
+ * @param int $itemId
+ * @param string $productSku
+ * @param StockItemInterface $stockItem
+ * @return int
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function afterUpdateStockItemBySku(
+ StockRegistryInterface $subject,
+ int $itemId,
+ string $productSku,
+ StockItemInterface $stockItem
+ ): int {
+ // Remove cache to get updated legacy stock item on the next request.
+ $this->legacyStockItemCacheStorage->delete($productSku);
+
+ $productType = $this->getProductTypesBySkus->execute([$productSku])[$productSku];
+
+ $stockItemConfiguration = $this->getStockItemConfiguration->execute($productSku, Stock::DEFAULT_STOCK_ID);
+ if ($stockItemConfiguration->isManageStock() === false
+ || $stockItemConfiguration->isUseConfigManageStock() === false
+ ) {
+ $this->setDataToLegacyStockStatus->execute($productSku, (float)$stockItem->getQty(), 1);
+ } else {
+ if ($this->isSourceItemManagementAllowedForProductType->execute($productType)
+ && $stockItem->getQty() !== null
+ ) {
+ $this->setDataToLegacyStockStatus->execute(
+ $productSku,
+ (float)$stockItem->getQty(),
+ $stockItem->getIsInStock()
+ );
+ }
+ }
+ return $itemId;
+ }
+}
diff --git a/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Api/StockRegistry/SetQtyToLegacyStock.php b/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Api/StockRegistry/SetQtyToLegacyStock.php
new file mode 100644
index 000000000000..6f890049c939
--- /dev/null
+++ b/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/Api/StockRegistry/SetQtyToLegacyStock.php
@@ -0,0 +1,54 @@
+request = $request;
+ }
+
+ /**
+ * Set qty to legacy stock.
+ *
+ * @param StockRegistryInterface $subject
+ * @param string $productSku
+ * @param StockItemInterface $stockItem
+ * @return array
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeUpdateStockItemBySku(
+ StockRegistryInterface $subject,
+ string $productSku,
+ StockItemInterface $stockItem
+ ): array {
+ $sources = $this->request->getParam('sources', []);
+ if (isset($sources['assigned_sources']) && is_array($sources['assigned_sources'])) {
+ foreach ($sources['assigned_sources'] as $source) {
+ if ($source['name'] === 'Default Source') {
+ $stockItem->setQty($source['quantity']);
+ break;
+ }
+ }
+ }
+ return [$productSku, $stockItem];
+ }
+}
diff --git a/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/UpdateSourceItemAtLegacyStockItemSavePlugin.php b/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/UpdateSourceItemAtLegacyStockItemSavePlugin.php
index a9de68821e3e..c695c1d71a9b 100755
--- a/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/UpdateSourceItemAtLegacyStockItemSavePlugin.php
+++ b/vendor/magento/module-inventory-catalog/Plugin/CatalogInventory/UpdateSourceItemAtLegacyStockItemSavePlugin.php
@@ -7,19 +7,25 @@
namespace Magento\InventoryCatalog\Plugin\CatalogInventory;
+use Exception;
use Magento\CatalogInventory\Model\ResourceModel\Stock\Item as ItemResourceModel;
+use Magento\CatalogInventory\Model\Stock;
use Magento\CatalogInventory\Model\Stock\Item;
use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\Exception\InputException;
use Magento\Framework\Model\AbstractModel;
use Magento\InventoryCatalog\Model\GetDefaultSourceItemBySku;
+use Magento\InventoryCatalog\Model\ResourceModel\SetDataToLegacyStockStatus;
use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface;
use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface;
use Magento\InventoryCatalog\Model\UpdateSourceItemBasedOnLegacyStockItem;
use Magento\InventoryConfigurationApi\Model\IsSourceItemManagementAllowedForProductTypeInterface;
+use Magento\InventorySalesApi\Api\AreProductsSalableInterface;
/**
* Class provides around Plugin on \Magento\CatalogInventory\Model\ResourceModel\Stock\Item::save
* to update data in Inventory source item based on legacy Stock Item data
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class UpdateSourceItemAtLegacyStockItemSavePlugin
{
@@ -53,6 +59,16 @@ class UpdateSourceItemAtLegacyStockItemSavePlugin
*/
private $getDefaultSourceItemBySku;
+ /**
+ * @var AreProductsSalableInterface
+ */
+ private $areProductsSalable;
+
+ /**
+ * @var SetDataToLegacyStockStatus
+ */
+ private $setDataToLegacyStockStatus;
+
/**
* @param UpdateSourceItemBasedOnLegacyStockItem $updateSourceItemBasedOnLegacyStockItem
* @param ResourceConnection $resourceConnection
@@ -60,6 +76,8 @@ class UpdateSourceItemAtLegacyStockItemSavePlugin
* @param GetProductTypesBySkusInterface $getProductTypeBySku
* @param GetSkusByProductIdsInterface $getSkusByProductIds
* @param GetDefaultSourceItemBySku $getDefaultSourceItemBySku
+ * @param AreProductsSalableInterface $areProductsSalable
+ * @param SetDataToLegacyStockStatus $setDataToLegacyStockStatus
*/
public function __construct(
UpdateSourceItemBasedOnLegacyStockItem $updateSourceItemBasedOnLegacyStockItem,
@@ -67,7 +85,9 @@ public function __construct(
IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType,
GetProductTypesBySkusInterface $getProductTypeBySku,
GetSkusByProductIdsInterface $getSkusByProductIds,
- GetDefaultSourceItemBySku $getDefaultSourceItemBySku
+ GetDefaultSourceItemBySku $getDefaultSourceItemBySku,
+ AreProductsSalableInterface $areProductsSalable,
+ SetDataToLegacyStockStatus $setDataToLegacyStockStatus
) {
$this->updateSourceItemBasedOnLegacyStockItem = $updateSourceItemBasedOnLegacyStockItem;
$this->resourceConnection = $resourceConnection;
@@ -75,14 +95,18 @@ public function __construct(
$this->getProductTypeBySku = $getProductTypeBySku;
$this->getSkusByProductIds = $getSkusByProductIds;
$this->getDefaultSourceItemBySku = $getDefaultSourceItemBySku;
+ $this->areProductsSalable = $areProductsSalable;
+ $this->setDataToLegacyStockStatus = $setDataToLegacyStockStatus;
}
/**
+ * Update source item for legacy stock.
+ *
* @param ItemResourceModel $subject
* @param callable $proceed
* @param AbstractModel $legacyStockItem
* @return ItemResourceModel
- * @throws \Exception
+ * @throws Exception
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
@@ -99,12 +123,25 @@ public function aroundSave(ItemResourceModel $subject, callable $proceed, Abstra
if ($this->shouldAlignDefaultSourceWithLegacy($legacyStockItem)) {
$this->updateSourceItemBasedOnLegacyStockItem->execute($legacyStockItem);
}
+
+ $productSku = $this->getSkusByProductIds
+ ->execute([$legacyStockItem->getProductId()])[$legacyStockItem->getProductId()];
+ $stockStatuses = [];
+ $areSalableResults = $this->areProductsSalable->execute([$productSku], Stock::DEFAULT_STOCK_ID);
+ foreach ($areSalableResults as $productSalable) {
+ $stockStatuses[$productSalable->getSku()] = $productSalable->isSalable();
+ }
+ $this->setDataToLegacyStockStatus->execute(
+ $productSku,
+ (float) $legacyStockItem->getQty(),
+ $stockStatuses[(string)$productSku] === true ? 1 : 0
+ );
}
$connection->commit();
return $subject;
- } catch (\Exception $e) {
+ } catch (Exception $e) {
$connection->rollBack();
throw $e;
}
@@ -112,9 +149,10 @@ public function aroundSave(ItemResourceModel $subject, callable $proceed, Abstra
/**
* Return true if legacy stock item should update default source (if existing)
+ *
* @param Item $legacyStockItem
* @return bool
- * @throws \Magento\Framework\Exception\InputException
+ * @throws InputException
*/
private function shouldAlignDefaultSourceWithLegacy(Item $legacyStockItem): bool
{
@@ -129,9 +167,11 @@ private function shouldAlignDefaultSourceWithLegacy(Item $legacyStockItem): bool
}
/**
+ * Returns product type id.
+ *
* @param Item $legacyStockItem
* @return string
- * @throws \Magento\Framework\Exception\InputException
+ * @throws InputException
*/
private function getTypeId(Item $legacyStockItem): string
{
diff --git a/vendor/magento/module-inventory-catalog/etc/di.xml b/vendor/magento/module-inventory-catalog/etc/di.xml
index 2910bc2ca1b0..29bb39faa6f6 100644
--- a/vendor/magento/module-inventory-catalog/etc/di.xml
+++ b/vendor/magento/module-inventory-catalog/etc/di.xml
@@ -100,6 +100,8 @@
+
+
+
+
+
+ - Magento\InventoryCatalog\Model\ResourceModel\StockStatusExpressionForDefaultStock
+ - Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\StatusExpression\DefaultExpression
+ - Magento\CatalogInventory\Model\ResourceModel\Indexer\Stock\StatusExpression\DefaultExpression
+
+
+
diff --git a/vendor/magento/module-inventory-configurable-product/Plugin/CatalogInventory/Api/StockRegistry/SetQtyToLegacyStock.php b/vendor/magento/module-inventory-configurable-product/Plugin/CatalogInventory/Api/StockRegistry/SetQtyToLegacyStock.php
new file mode 100644
index 000000000000..f0c980a86057
--- /dev/null
+++ b/vendor/magento/module-inventory-configurable-product/Plugin/CatalogInventory/Api/StockRegistry/SetQtyToLegacyStock.php
@@ -0,0 +1,56 @@
+request = $request;
+ }
+
+ /**
+ * Set qty to legacy stock.
+ *
+ * @param StockRegistryInterface $subject
+ * @param string $productSku
+ * @param StockItemInterface $stockItem
+ * @return array
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeUpdateStockItemBySku(
+ StockRegistryInterface $subject,
+ string $productSku,
+ StockItemInterface $stockItem
+ ): array {
+ $configurableOptions = $this->request->getParam('quantity_resolver', []);
+ if (isset($configurableOptions['dynamicRows']['dynamicRows'])
+ && is_array($configurableOptions['dynamicRows']['dynamicRows'])
+ ) {
+ foreach ($configurableOptions['dynamicRows']['dynamicRows'] as $source) {
+ if ($source['source'] === 'Default Source') {
+ $stockItem->setQty($source['quantity_per_source']);
+ break;
+ }
+ }
+ }
+ return [$productSku, $stockItem];
+ }
+}
diff --git a/vendor/magento/module-inventory-configurable-product/Plugin/CatalogInventory/Observer/ParentItemProcessor/AdaptParentItemProcessorPlugin.php b/vendor/magento/module-inventory-configurable-product/Plugin/CatalogInventory/Observer/ParentItemProcessor/AdaptParentItemProcessorPlugin.php
index f7543ca34e4b..33bb05564c45 100644
--- a/vendor/magento/module-inventory-configurable-product/Plugin/CatalogInventory/Observer/ParentItemProcessor/AdaptParentItemProcessorPlugin.php
+++ b/vendor/magento/module-inventory-configurable-product/Plugin/CatalogInventory/Observer/ParentItemProcessor/AdaptParentItemProcessorPlugin.php
@@ -7,9 +7,14 @@
namespace Magento\InventoryConfigurableProduct\Plugin\CatalogInventory\Observer\ParentItemProcessor;
+use Closure;
use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\CatalogInventory\Observer\ParentItemProcessorInterface;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\InventoryCatalogApi\Model\GetSkusByProductIdsInterface;
use Magento\InventoryCatalogApi\Model\IsSingleSourceModeInterface;
+use Magento\InventoryIndexer\Model\ResourceModel\UpdateLegacyStockStatus;
/**
* Process configurable product stock status.
@@ -21,29 +26,77 @@ class AdaptParentItemProcessorPlugin
*/
private $isSingleSourceMode;
+ /**
+ * @var GetSkusByProductIdsInterface
+ */
+ private $getSkusByProductIds;
+
+ /**
+ * @var Configurable
+ */
+ private $configurableType;
+
+ /**
+ * @var UpdateLegacyStockStatus
+ */
+ private $updateLegacyStockStatus;
+
+ /**
+ * @var StockRegistryInterface
+ */
+ private $stockRegistry;
+
/**
* @param IsSingleSourceModeInterface $isSingleSourceMode
+ * @param GetSkusByProductIdsInterface $getSkusByProductIds
+ * @param Configurable $configurableType
+ * @param UpdateLegacyStockStatus $updateLegacyStockStatus
+ * @param StockRegistryInterface $stockRegistry
*/
- public function __construct(IsSingleSourceModeInterface $isSingleSourceMode)
- {
+ public function __construct(
+ IsSingleSourceModeInterface $isSingleSourceMode,
+ GetSkusByProductIdsInterface $getSkusByProductIds,
+ Configurable $configurableType,
+ UpdateLegacyStockStatus $updateLegacyStockStatus,
+ StockRegistryInterface $stockRegistry
+ ) {
$this->isSingleSourceMode = $isSingleSourceMode;
+ $this->getSkusByProductIds = $getSkusByProductIds;
+ $this->configurableType = $configurableType;
+ $this->updateLegacyStockStatus = $updateLegacyStockStatus;
+ $this->stockRegistry = $stockRegistry;
}
/**
* Process configurable product stock status considering source mode.
*
* @param ParentItemProcessorInterface $subject
- * @param \Closure $proceed
+ * @param Closure $proceed
* @param ProductInterface $product
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function aroundProcess(
ParentItemProcessorInterface $subject,
- \Closure $proceed,
+ Closure $proceed,
ProductInterface $product
): void {
if ($this->isSingleSourceMode->execute()) {
$proceed($product);
+ } else {
+ $stockItem = $this->stockRegistry->getStockItem($product->getId());
+ if (!$stockItem->getManageStock() && !$stockItem->getUseConfigManageStock()) {
+ $parentIds = $this->configurableType->getParentIdsByChild($product->getId());
+ $skus = $this->getSkusByProductIds->execute($parentIds);
+
+ $dataForUpdate = [];
+ foreach ($parentIds as $parentId) {
+ $parentStockItem = $this->stockRegistry->getStockItem($parentId);
+ if ($parentStockItem->getIsInStock()) {
+ $dataForUpdate[$skus[$parentId]] = true;
+ }
+ }
+ $this->updateLegacyStockStatus->execute($dataForUpdate);
+ }
}
}
}
diff --git a/vendor/magento/module-inventory-configurable-product/etc/di.xml b/vendor/magento/module-inventory-configurable-product/etc/di.xml
index babb1c0177ce..93313cc5fbc8 100644
--- a/vendor/magento/module-inventory-configurable-product/etc/di.xml
+++ b/vendor/magento/module-inventory-configurable-product/etc/di.xml
@@ -31,4 +31,8 @@
Magento\InventoryConfigurableProduct\Pricing\Price\Indexer\BaseStockStatusSelectProcessor
+
+
+
diff --git a/vendor/magento/module-inventory-configuration/Model/LegacyStockItem/CacheStorage.php b/vendor/magento/module-inventory-configuration/Model/LegacyStockItem/CacheStorage.php
new file mode 100644
index 000000000000..e44e57e3984e
--- /dev/null
+++ b/vendor/magento/module-inventory-configuration/Model/LegacyStockItem/CacheStorage.php
@@ -0,0 +1,50 @@
+cachedItems[$sku] = $item;
+ }
+
+ /**
+ * Get item from cache
+ *
+ * @param string $sku
+ * @return StockItemInterface
+ */
+ public function get(string $sku): ?StockItemInterface
+ {
+ return $this->cachedItems[$sku] ?? null;
+ }
+
+ /**
+ * Delete item from cache
+ *
+ * @param string $sku
+ */
+ public function delete(string $sku): void
+ {
+ unset($this->cachedItems[$sku]);
+ }
+}
diff --git a/vendor/magento/module-inventory-configuration/Plugin/InventoryConfiguration/Model/GetLegacyStockItemCache.php b/vendor/magento/module-inventory-configuration/Plugin/InventoryConfiguration/Model/GetLegacyStockItemCache.php
index 46538612d80f..69a4646e4866 100644
--- a/vendor/magento/module-inventory-configuration/Plugin/InventoryConfiguration/Model/GetLegacyStockItemCache.php
+++ b/vendor/magento/module-inventory-configuration/Plugin/InventoryConfiguration/Model/GetLegacyStockItemCache.php
@@ -9,6 +9,7 @@
use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\InventoryConfiguration\Model\GetLegacyStockItem;
+use Magento\InventoryConfiguration\Model\LegacyStockItem\CacheStorage;
/**
* Caching plugin for GetLegacyStockItem service.
@@ -16,9 +17,17 @@
class GetLegacyStockItemCache
{
/**
- * @var array
+ * @var CacheStorage
*/
- private $legacyStockItemsBySku = [];
+ private $cacheStorage;
+
+ /**
+ * @param CacheStorage $cacheStorage
+ */
+ public function __construct(CacheStorage $cacheStorage)
+ {
+ $this->cacheStorage = $cacheStorage;
+ }
/**
* Cache the result of service to avoid duplicate queries to the database.
@@ -31,15 +40,15 @@ class GetLegacyStockItemCache
*/
public function aroundExecute(GetLegacyStockItem $subject, callable $proceed, string $sku): StockItemInterface
{
- if (isset($this->legacyStockItemsBySku[$sku])) {
- return $this->legacyStockItemsBySku[$sku];
+ if ($this->cacheStorage->get($sku)) {
+ return $this->cacheStorage->get($sku);
}
/** @var StockItemInterface $item */
$item = $proceed($sku);
/* Avoid add to cache a new item */
if ($item->getItemId()) {
- $this->legacyStockItemsBySku[$sku] = $item;
+ $this->cacheStorage->set($sku, $item);
}
return $item;
diff --git a/vendor/magento/module-inventory-indexer/Indexer/SelectBuilder.php b/vendor/magento/module-inventory-indexer/Indexer/SelectBuilder.php
index dc63c6d54719..5d5aa78acc26 100644
--- a/vendor/magento/module-inventory-indexer/Indexer/SelectBuilder.php
+++ b/vendor/magento/module-inventory-indexer/Indexer/SelectBuilder.php
@@ -15,6 +15,7 @@
use Magento\Inventory\Model\StockSourceLink;
use Magento\InventoryApi\Api\Data\SourceInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterface;
+use Magento\InventoryIndexer\Indexer\Stock\ReservationsIndexTable;
use Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\GetIsStockItemSalableConditionInterface;
/**
@@ -37,19 +38,27 @@ class SelectBuilder implements SelectBuilderInterface
*/
private $productTableName;
+ /**
+ * @var ReservationsIndexTable
+ */
+ private $reservationsIndexTable;
+
/**
* @param ResourceConnection $resourceConnection
* @param GetIsStockItemSalableConditionInterface $getIsStockItemSalableCondition
* @param string $productTableName
+ * @param ReservationsIndexTable $reservationsIndexTable
*/
public function __construct(
ResourceConnection $resourceConnection,
GetIsStockItemSalableConditionInterface $getIsStockItemSalableCondition,
- string $productTableName
+ string $productTableName,
+ ReservationsIndexTable $reservationsIndexTable
) {
$this->resourceConnection = $resourceConnection;
$this->getIsStockItemSalableCondition = $getIsStockItemSalableCondition;
$this->productTableName = $productTableName;
+ $this->reservationsIndexTable = $reservationsIndexTable;
}
/**
@@ -66,7 +75,7 @@ public function execute(int $stockId): Select
$quantityExpression = (string)$this->resourceConnection->getConnection()->getCheckSql(
'source_item.' . SourceItemInterface::STATUS . ' = ' . SourceItemInterface::STATUS_OUT_OF_STOCK,
0,
- SourceItemInterface::QUANTITY
+ 'source_item.' . SourceItemInterface::QUANTITY
);
$sourceCodes = $this->getSourceCodes($stockId);
@@ -79,6 +88,14 @@ public function execute(int $stockId): Select
['legacy_stock_item' => $this->resourceConnection->getTableName('cataloginventory_stock_item')],
'product.entity_id = legacy_stock_item.product_id',
[]
+ )->joinLeft(
+ [
+ 'reservations' => $this->resourceConnection->getTableName(
+ $this->reservationsIndexTable->getTableName($stockId)
+ )
+ ],
+ ' source_item.' . SourceItemInterface::SKU . ' = reservations.sku',
+ []
);
$select->from(
@@ -90,7 +107,7 @@ public function execute(int $stockId): Select
]
)
->where('source_item.' . SourceItemInterface::SOURCE_CODE . ' IN (?)', $sourceCodes)
- ->group([SourceItemInterface::SKU]);
+ ->group(['source_item.' .SourceItemInterface::SKU]);
return $select;
}
@@ -119,7 +136,6 @@ private function getSourceCodes(int $stockId): array
->where('stock_source_link.' . StockSourceLink::STOCK_ID . ' = ?', $stockId)
->where(SourceInterface::ENABLED . ' = ?', 1);
- $sourceCodes = $connection->fetchCol($select);
- return $sourceCodes;
+ return $connection->fetchCol($select);
}
}
diff --git a/vendor/magento/module-inventory-indexer/Indexer/SourceItem/Strategy/Sync.php b/vendor/magento/module-inventory-indexer/Indexer/SourceItem/Strategy/Sync.php
index 85851a5942e7..678e446d1d9f 100644
--- a/vendor/magento/module-inventory-indexer/Indexer/SourceItem/Strategy/Sync.php
+++ b/vendor/magento/module-inventory-indexer/Indexer/SourceItem/Strategy/Sync.php
@@ -7,11 +7,14 @@
namespace Magento\InventoryIndexer\Indexer\SourceItem\Strategy;
+use ArrayIterator;
use Magento\Framework\App\ResourceConnection;
use Magento\InventoryCatalogApi\Api\DefaultStockProviderInterface;
use Magento\InventoryIndexer\Indexer\InventoryIndexer;
use Magento\InventoryIndexer\Indexer\SourceItem\GetSkuListInStock;
use Magento\InventoryIndexer\Indexer\SourceItem\IndexDataBySkuListProvider;
+use Magento\InventoryIndexer\Indexer\Stock\PrepareReservationsIndexData;
+use Magento\InventoryIndexer\Indexer\Stock\ReservationsIndexTable;
use Magento\InventoryIndexer\Indexer\Stock\StockIndexer;
use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias;
use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface;
@@ -20,6 +23,7 @@
/**
* Reindex source items synchronously.
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Sync
{
@@ -58,6 +62,16 @@ class Sync
*/
private $defaultStockProvider;
+ /**
+ * @var ReservationsIndexTable
+ */
+ private $reservationsIndexTable;
+
+ /**
+ * @var PrepareReservationsIndexData
+ */
+ private $prepareReservationsIndexData;
+
/**
* $indexStructure is reserved name for construct variable (in index internal mechanism)
*
@@ -68,6 +82,8 @@ class Sync
* @param IndexNameBuilder $indexNameBuilder
* @param StockIndexer $stockIndexer
* @param DefaultStockProviderInterface $defaultStockProvider
+ * @param ReservationsIndexTable $reservationsIndexTable
+ * @param PrepareReservationsIndexData $prepareReservationsIndexData
*/
public function __construct(
GetSkuListInStock $getSkuListInStockToUpdate,
@@ -76,7 +92,9 @@ public function __construct(
IndexDataBySkuListProvider $indexDataBySkuListProvider,
IndexNameBuilder $indexNameBuilder,
StockIndexer $stockIndexer,
- DefaultStockProviderInterface $defaultStockProvider
+ DefaultStockProviderInterface $defaultStockProvider,
+ ReservationsIndexTable $reservationsIndexTable,
+ PrepareReservationsIndexData $prepareReservationsIndexData
) {
$this->getSkuListInStock = $getSkuListInStockToUpdate;
$this->indexStructure = $indexStructureHandler;
@@ -85,6 +103,8 @@ public function __construct(
$this->indexNameBuilder = $indexNameBuilder;
$this->stockIndexer = $stockIndexer;
$this->defaultStockProvider = $defaultStockProvider;
+ $this->reservationsIndexTable = $reservationsIndexTable;
+ $this->prepareReservationsIndexData = $prepareReservationsIndexData;
}
/**
@@ -116,16 +136,21 @@ public function executeList(array $sourceItemIds) : void
$this->indexHandler->cleanIndex(
$mainIndexName,
- new \ArrayIterator($skuList),
+ new ArrayIterator($skuList),
ResourceConnection::DEFAULT_CONNECTION
);
+ $this->reservationsIndexTable->createTable($stockId);
+ $this->prepareReservationsIndexData->execute($stockId);
+
$indexData = $this->indexDataBySkuListProvider->execute($stockId, $skuList);
$this->indexHandler->saveIndex(
$mainIndexName,
$indexData,
ResourceConnection::DEFAULT_CONNECTION
);
+
+ $this->reservationsIndexTable->dropTable($stockId);
}
}
diff --git a/vendor/magento/module-inventory-indexer/Indexer/Stock/PrepareReservationsIndexData.php b/vendor/magento/module-inventory-indexer/Indexer/Stock/PrepareReservationsIndexData.php
new file mode 100644
index 000000000000..c80aec1331c0
--- /dev/null
+++ b/vendor/magento/module-inventory-indexer/Indexer/Stock/PrepareReservationsIndexData.php
@@ -0,0 +1,62 @@
+resourceConnection = $resourceConnection;
+ $this->reservationsIndexTable = $reservationsIndexTable;
+ }
+
+ /**
+ * Prepare reservation index data.
+ *
+ * @param int $stockId
+ * @return void
+ */
+ public function execute(int $stockId): void
+ {
+ $connection = $this->resourceConnection->getConnection();
+ $reservationsData = $connection->select();
+ $reservationsData->from(
+ ['reservations' => $this->resourceConnection->getTableName('inventory_reservation')],
+ [
+ 'sku',
+ 'reservation_qty' => 'SUM(reservations.quantity)'
+ ]
+ );
+ $reservationsData->where('stock_id = ?', $stockId);
+ $reservationsData->group(['sku', 'stock_id']);
+
+ $insertFromSelect = $connection->insertFromSelect(
+ $reservationsData,
+ $this->reservationsIndexTable->getTableName($stockId)
+ );
+ $connection->query($insertFromSelect);
+ }
+}
diff --git a/vendor/magento/module-inventory-indexer/Indexer/Stock/ReservationsIndexTable.php b/vendor/magento/module-inventory-indexer/Indexer/Stock/ReservationsIndexTable.php
new file mode 100644
index 000000000000..e18562828b56
--- /dev/null
+++ b/vendor/magento/module-inventory-indexer/Indexer/Stock/ReservationsIndexTable.php
@@ -0,0 +1,93 @@
+resourceConnection = $resourceConnection;
+ }
+
+ /**
+ * Create temporary index table
+ *
+ * @param int $stockId
+ * @throws \Zend_Db_Exception
+ */
+ public function createTable(int $stockId): void
+ {
+ $connection = $this->resourceConnection->getConnection();
+ $reservationsTableName = $this->getTableName($stockId);
+ $table = $connection->newTable($reservationsTableName);
+ $table->addColumn(
+ 'sku',
+ Table::TYPE_TEXT,
+ 64,
+ [
+ Table::OPTION_PRIMARY => true,
+ Table::OPTION_NULLABLE => false,
+ ],
+ 'Sku'
+ );
+ $table->addColumn(
+ 'reservation_qty',
+ Table::TYPE_DECIMAL,
+ null,
+ [
+ Table::OPTION_UNSIGNED => false,
+ Table::OPTION_NULLABLE => false,
+ Table::OPTION_DEFAULT => 0,
+ Table::OPTION_PRECISION => 10,
+ Table::OPTION_SCALE => 4,
+ ],
+ 'Reservation Qty'
+ );
+ $table->addIndex(
+ 'index_sku_qty',
+ ['sku'],
+ ['type' => AdapterInterface::INDEX_TYPE_INDEX]
+ );
+ $connection->dropTemporaryTable($reservationsTableName);
+ $connection->createTemporaryTable($table);
+ }
+
+ /**
+ * Return temporary table name.
+ *
+ * @param int $stockId
+ * @return string
+ */
+ public function getTableName(int $stockId): string
+ {
+ return 'reservations_temp_for_stock_' . $stockId;
+ }
+
+ /**
+ * Drop temporary index table.
+ *
+ * @param int $stockId
+ */
+ public function dropTable(int $stockId): void
+ {
+ $connection = $this->resourceConnection->getConnection();
+ $connection->dropTemporaryTable($this->getTableName($stockId));
+ }
+}
diff --git a/vendor/magento/module-inventory-indexer/Indexer/Stock/Strategy/Sync.php b/vendor/magento/module-inventory-indexer/Indexer/Stock/Strategy/Sync.php
index fb5d6506a320..e118d614e2f9 100644
--- a/vendor/magento/module-inventory-indexer/Indexer/Stock/Strategy/Sync.php
+++ b/vendor/magento/module-inventory-indexer/Indexer/Stock/Strategy/Sync.php
@@ -11,6 +11,8 @@
use Magento\InventoryIndexer\Indexer\InventoryIndexer;
use Magento\InventoryIndexer\Indexer\Stock\GetAllStockIds;
use Magento\InventoryIndexer\Indexer\Stock\IndexDataProviderByStockId;
+use Magento\InventoryIndexer\Indexer\Stock\PrepareReservationsIndexData;
+use Magento\InventoryIndexer\Indexer\Stock\ReservationsIndexTable;
use Magento\InventoryMultiDimensionalIndexerApi\Model\Alias;
use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexHandlerInterface;
use Magento\InventoryMultiDimensionalIndexerApi\Model\IndexNameBuilder;
@@ -57,6 +59,16 @@ class Sync
*/
private $defaultStockProvider;
+ /**
+ * @var ReservationsIndexTable
+ */
+ private $reservationsIndexTable;
+
+ /**
+ * @var PrepareReservationsIndexData
+ */
+ private $prepareReservationsIndexData;
+
/**
* $indexStructure is reserved name for construct variable in index internal mechanism
*
@@ -67,6 +79,8 @@ class Sync
* @param IndexDataProviderByStockId $indexDataProviderByStockId
* @param IndexTableSwitcherInterface $indexTableSwitcher
* @param DefaultStockProviderInterface $defaultStockProvider
+ * @param ReservationsIndexTable $reservationsIndexTable
+ * @param PrepareReservationsIndexData $prepareReservationsIndexData
*/
public function __construct(
GetAllStockIds $getAllStockIds,
@@ -75,7 +89,9 @@ public function __construct(
IndexNameBuilder $indexNameBuilder,
IndexDataProviderByStockId $indexDataProviderByStockId,
IndexTableSwitcherInterface $indexTableSwitcher,
- DefaultStockProviderInterface $defaultStockProvider
+ DefaultStockProviderInterface $defaultStockProvider,
+ ReservationsIndexTable $reservationsIndexTable,
+ PrepareReservationsIndexData $prepareReservationsIndexData
) {
$this->getAllStockIds = $getAllStockIds;
$this->indexStructure = $indexStructureHandler;
@@ -84,6 +100,8 @@ public function __construct(
$this->indexDataProviderByStockId = $indexDataProviderByStockId;
$this->indexTableSwitcher = $indexTableSwitcher;
$this->defaultStockProvider = $defaultStockProvider;
+ $this->reservationsIndexTable = $reservationsIndexTable;
+ $this->prepareReservationsIndexData = $prepareReservationsIndexData;
}
/**
@@ -140,6 +158,9 @@ public function executeList(array $stockIds): void
$this->indexStructure->create($mainIndexName, ResourceConnection::DEFAULT_CONNECTION);
}
+ $this->reservationsIndexTable->createTable($stockId);
+ $this->prepareReservationsIndexData->execute($stockId);
+
$this->indexHandler->saveIndex(
$replicaIndexName,
$this->indexDataProviderByStockId->execute((int)$stockId),
@@ -147,6 +168,8 @@ public function executeList(array $stockIds): void
);
$this->indexTableSwitcher->switch($mainIndexName, ResourceConnection::DEFAULT_CONNECTION);
$this->indexStructure->delete($replicaIndexName, ResourceConnection::DEFAULT_CONNECTION);
+
+ $this->reservationsIndexTable->dropTable($stockId);
}
}
}
diff --git a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php
index fb93eb8a3b5c..8ab63e35ba8c 100644
--- a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php
+++ b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/IsStockItemSalableConditionChain.php
@@ -21,6 +21,11 @@ class IsStockItemSalableConditionChain implements GetIsStockItemSalableCondition
*/
private $conditions = [];
+ /**
+ * @var GetIsStockItemSalableConditionInterface[]
+ */
+ private $requiredConditions = [];
+
/**
* @var ResourceConnection
*/
@@ -29,12 +34,13 @@ class IsStockItemSalableConditionChain implements GetIsStockItemSalableCondition
/**
* @param ResourceConnection $resourceConnection
* @param array $conditions
- *
+ * @param array $requiredConditions
* @throws LocalizedException
*/
public function __construct(
ResourceConnection $resourceConnection,
- array $conditions = []
+ array $conditions = [],
+ array $requiredConditions = []
) {
foreach ($conditions as $getIsSalableCondition) {
if (!$getIsSalableCondition instanceof GetIsStockItemSalableConditionInterface) {
@@ -43,8 +49,16 @@ public function __construct(
);
}
}
+ foreach ($requiredConditions as $getIsSalableCondition) {
+ if (!$getIsSalableCondition instanceof GetIsStockItemSalableConditionInterface) {
+ throw new LocalizedException(
+ __('Condition must implement %1', GetIsStockItemSalableConditionInterface::class)
+ );
+ }
+ }
$this->resourceConnection = $resourceConnection;
$this->conditions = $conditions;
+ $this->requiredConditions = $requiredConditions;
}
/**
@@ -65,7 +79,20 @@ public function execute(Select $select): string
}
}
- $isSalableString = '(' . implode(') OR (', $conditionStrings) . ')';
+ if (empty($this->requiredConditions)) {
+ $isSalableString = '(' . implode(') OR (', $conditionStrings) . ')';
+ } else {
+ $requiredConditionsStrings = [];
+ foreach ($this->requiredConditions as $requiredCondition) {
+ $requiredConditionString = $requiredCondition->execute($select);
+ if ('' !== trim($requiredConditionString)) {
+ $requiredConditionsStrings[] = $requiredConditionString;
+ }
+ }
+ $isSalableString = '(' . implode(') AND (', $requiredConditionsStrings) . ')'
+ . ' AND ((' . implode(') OR (', $conditionStrings) . '))';
+ }
+
return (string)$this->resourceConnection->getConnection()->getCheckSql($isSalableString, 1, 0);
}
}
diff --git a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/MinQtyStockCondition.php b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/MinQtyStockCondition.php
index 6f74e532fbfa..05369ceec41d 100644
--- a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/MinQtyStockCondition.php
+++ b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/MinQtyStockCondition.php
@@ -50,7 +50,7 @@ public function execute(Select $select): string
$quantityExpression = (string)$this->resourceConnection->getConnection()->getCheckSql(
'source_item.' . SourceItemInterface::STATUS . ' = ' . SourceItemInterface::STATUS_OUT_OF_STOCK,
0,
- SourceItemInterface::QUANTITY
+ 'source_item.' . SourceItemInterface::QUANTITY
);
$quantityExpression = 'SUM(' . $quantityExpression . ')';
diff --git a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/ReservationsCondition.php b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/ReservationsCondition.php
new file mode 100644
index 000000000000..0970f78760a5
--- /dev/null
+++ b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/ReservationsCondition.php
@@ -0,0 +1,41 @@
+configuration = $configuration;
+ }
+
+ /**
+ * @inheritdoc
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function execute(Select $select): string
+ {
+ $globalMinQty = $this->configuration->getMinQty();
+ return 'reservations.reservation_qty IS NULL OR (SUM(source_item.'
+ . SourceItemInterface::QUANTITY
+ . ') + reservations.reservation_qty) > '
+ . $globalMinQty;
+ }
+}
diff --git a/vendor/magento/module-inventory-sales/etc/di.xml b/vendor/magento/module-inventory-sales/etc/di.xml
index 19faa0c3719d..12b95a877435 100644
--- a/vendor/magento/module-inventory-sales/etc/di.xml
+++ b/vendor/magento/module-inventory-sales/etc/di.xml
@@ -48,6 +48,9 @@
- Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\MinQtyStockCondition
- Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\SkuIsAbsentInCatalogCondition
+
+ - Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\ReservationsCondition
+