diff --git a/vendor/magento/module-inventory-indexer/etc/di.xml b/vendor/magento/module-inventory-indexer/etc/di.xml index 9b74e7c7dad..f5e9f061b97 100644 --- a/vendor/magento/module-inventory-indexer/etc/di.xml +++ b/vendor/magento/module-inventory-indexer/etc/di.xml @@ -95,4 +95,14 @@ catalog_product_entity + + + Magento\InventoryIndexer\Model\IsProductSalable + + + + + Magento\InventoryIndexer\Model\AreProductsSalable + + diff --git a/vendor/magento/module-inventory-sales/Model/GetProductAvailableQty.php b/vendor/magento/module-inventory-sales/Model/GetProductAvailableQty.php new file mode 100644 index 00000000000..5f47aa552e4 --- /dev/null +++ b/vendor/magento/module-inventory-sales/Model/GetProductAvailableQty.php @@ -0,0 +1,76 @@ +resourceConnection = $resourceConnection; + } + + /** + * Get available quantity for given SKU and Stock + * + * @param string $sku + * @param int $stockId + * @return float + */ + public function execute(string $sku, int $stockId): float + { + $connection = $this->resourceConnection->getConnection(); + $select = $connection->select()->from( + ['issl' => $this->resourceConnection->getTableName(StockSourceLink::TABLE_NAME_STOCK_SOURCE_LINK)], + [] + )->joinInner( + ['is' => $this->resourceConnection->getTableName(Source::TABLE_NAME_SOURCE)], + sprintf('issl.%s = is.%s', StockSourceLinkInterface::SOURCE_CODE, SourceInterface::SOURCE_CODE), + [] + )->joinInner( + ['isi' => $this->resourceConnection->getTableName(SourceItem::TABLE_NAME_SOURCE_ITEM)], + sprintf('issl.%s = isi.%s', StockSourceLinkInterface::SOURCE_CODE, SourceItemInterface::SOURCE_CODE), + [] + )->where( + sprintf('issl.%s = ?', StockSourceLinkInterface::STOCK_ID), + $stockId + )->where( + sprintf('is.%s = ?', SourceInterface::ENABLED), + 1 + )->where( + sprintf('isi.%s = ?', SourceItemInterface::SKU), + $sku + )->where( + sprintf('isi.%s = ?', SourceItemInterface::STATUS), + SourceItemInterface::STATUS_IN_STOCK + )->columns( + ['quantity' => new Zend_Db_Expr(sprintf('SUM(isi.%s)', SourceItemInterface::QUANTITY))] + ); + + return (float) $connection->fetchOne($select); + } +} diff --git a/vendor/magento/module-inventory-sales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php b/vendor/magento/module-inventory-sales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php index cc8dee8b5ba..e26925e6727 100644 --- a/vendor/magento/module-inventory-sales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php +++ b/vendor/magento/module-inventory-sales/Model/IsProductSalableCondition/IsSalableWithReservationsCondition.php @@ -11,6 +11,7 @@ use Magento\InventoryCatalogApi\Model\GetProductTypesBySkusInterface; use Magento\InventoryConfigurationApi\Model\IsSourceItemManagementAllowedForProductTypeInterface; use Magento\InventoryConfigurationApi\Api\Data\StockItemConfigurationInterface; use Magento\InventoryReservationsApi\Model\GetReservationsQuantityInterface; +use Magento\InventorySales\Model\GetProductAvailableQty; use Magento\InventorySalesApi\Api\IsProductSalableInterface; use Magento\InventorySalesApi\Model\GetStockItemDataInterface; use Magento\InventoryConfigurationApi\Api\GetStockItemConfigurationInterface; @@ -45,25 +46,33 @@ class IsSalableWithReservationsCondition implements IsProductSalableInterface */ private $getProductTypesBySkus; + /** + * @var GetProductAvailableQty + */ + private $getProductAvailableQty; + /** * @param GetStockItemDataInterface $getStockItemData * @param GetReservationsQuantityInterface $getReservationsQuantity * @param GetStockItemConfigurationInterface $getStockItemConfiguration * @param IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType * @param GetProductTypesBySkusInterface $getProductTypesBySkus + * @param GetProductAvailableQty $getProductAvailableQty */ public function __construct( GetStockItemDataInterface $getStockItemData, GetReservationsQuantityInterface $getReservationsQuantity, GetStockItemConfigurationInterface $getStockItemConfiguration, IsSourceItemManagementAllowedForProductTypeInterface $isSourceItemManagementAllowedForProductType, - GetProductTypesBySkusInterface $getProductTypesBySkus + GetProductTypesBySkusInterface $getProductTypesBySkus, + GetProductAvailableQty $getProductAvailableQty ) { $this->getStockItemData = $getStockItemData; $this->getReservationsQuantity = $getReservationsQuantity; $this->getStockItemConfiguration = $getStockItemConfiguration; $this->isSourceItemManagementAllowedForProductType = $isSourceItemManagementAllowedForProductType; $this->getProductTypesBySkus = $getProductTypesBySkus; + $this->getProductAvailableQty = $getProductAvailableQty; } /** @@ -84,7 +93,7 @@ class IsSalableWithReservationsCondition implements IsProductSalableInterface /** @var StockItemConfigurationInterface $stockItemConfiguration */ $stockItemConfiguration = $this->getStockItemConfiguration->execute($sku, $stockId); - $qtyWithReservation = $stockItemData[GetStockItemDataInterface::QUANTITY] + + $qtyWithReservation = $this->getProductAvailableQty->execute($sku, $stockId) + $this->getReservationsQuantity->execute($sku, $stockId); return $qtyWithReservation > $stockItemConfiguration->getMinQty(); diff --git a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/BackordersCondition.php b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/BackordersCondition.php index 60dedd6612e..74594829ef7 100644 --- a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/BackordersCondition.php +++ b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/BackordersCondition.php @@ -40,7 +40,12 @@ class BackordersCondition implements GetIsStockItemSalableConditionInterface $itemBackordersCondition = 'legacy_stock_item.backorders <> ' . StockItemConfigurationInterface::BACKORDERS_NO; $useDefaultBackorders = 'legacy_stock_item.use_config_backorders'; $itemMinQty = 'legacy_stock_item.min_qty'; - $itemQty = 'legacy_stock_item.qty'; + $globalMinQty = (float) $this->configuration->getMinQty(); + $minQty = (string) $select->getConnection()->getCheckSql( + 'legacy_stock_item.use_config_min_qty = 1', + $globalMinQty, + $itemMinQty + ); $isBackorderEnabled = $globalBackorders === StockItemConfigurationInterface::BACKORDERS_NO ? $useDefaultBackorders . ' = ' . StockItemConfigurationInterface::BACKORDERS_NO . ' AND ' . @@ -55,6 +60,6 @@ class BackordersCondition implements GetIsStockItemSalableConditionInterface 1 ); - return "($isBackorderEnabled) AND ($itemMinQty >= 0 OR $itemQty > $itemMinQty) AND SUM($isAnyStockItemInStock)"; + return "($isBackorderEnabled) AND ($minQty >= 0) AND SUM($isAnyStockItemInStock)"; } } diff --git a/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/MinQtyStockWithReservationsCondition.php b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/MinQtyStockWithReservationsCondition.php new file mode 100644 index 00000000000..2844815bb79 --- /dev/null +++ b/vendor/magento/module-inventory-sales/Model/ResourceModel/IsStockItemSalableCondition/MinQtyStockWithReservationsCondition.php @@ -0,0 +1,59 @@ +configuration = $configuration; + } + + /** + * @inheritdoc + */ + public function execute(Select $select): string + { + $globalMinQty = (float) $this->configuration->getMinQty(); + $itemMinQty = 'legacy_stock_item.min_qty'; + $inStockQty = (string) $select->getConnection()->getCheckSql( + 'source_item.' . SourceItemInterface::STATUS . ' = ' . SourceItemInterface::STATUS_OUT_OF_STOCK, + 0, + 'source_item.' . SourceItemInterface::QUANTITY + ); + $inStockQty = 'SUM(' . $inStockQty . ')'; + $minQty = (string) $select->getConnection()->getCheckSql( + 'legacy_stock_item.use_config_min_qty = 1', + $globalMinQty, + $itemMinQty + ); + $reservationQty = (string) $select->getConnection()->getCheckSql( + 'reservations.reservation_qty IS NULL', + 0, + 'reservations.reservation_qty' + ); + + return "$inStockQty + $reservationQty - $minQty > 0"; + } +} diff --git a/vendor/magento/module-inventory-sales/etc/di.xml b/vendor/magento/module-inventory-sales/etc/di.xml index 12b95a87743..70329af3ef8 100644 --- a/vendor/magento/module-inventory-sales/etc/di.xml +++ b/vendor/magento/module-inventory-sales/etc/di.xml @@ -45,12 +45,9 @@ Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\BackordersCondition Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\ManageStockCondition - Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\MinQtyStockCondition + Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\MinQtyStockWithReservationsCondition Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\SkuIsAbsentInCatalogCondition - - Magento\InventorySales\Model\ResourceModel\IsStockItemSalableCondition\ReservationsCondition -