From 0c63d9227c33043718a708e95af607191f2eb744 Mon Sep 17 00:00:00 2001 From: RomanKis Date: Tue, 24 Apr 2018 13:00:27 +0300 Subject: [PATCH] MSI-1015: Cannot Place Order with Configurable Product on Custom Stock. --- .../Model/CheckItemsQuantity.php | 7 ++- .../IsSalableWithReservationsCondition.php | 48 +++++++++++++++---- app/code/Magento/InventorySales/composer.json | 1 + 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/InventorySales/Model/CheckItemsQuantity.php b/app/code/Magento/InventorySales/Model/CheckItemsQuantity.php index 8ec12c0ad244..b5997fca9f34 100644 --- a/app/code/Magento/InventorySales/Model/CheckItemsQuantity.php +++ b/app/code/Magento/InventorySales/Model/CheckItemsQuantity.php @@ -7,6 +7,7 @@ namespace Magento\InventorySales\Model; +use Magento\ConfigurableProduct\Model\Product\Type\Configurable; use Magento\Framework\Exception\LocalizedException; use Magento\InventoryCatalog\Model\GetProductTypesBySkusInterface; use Magento\InventorySalesApi\Api\IsProductSalableForRequestedQtyInterface; @@ -67,11 +68,13 @@ public function execute(array $items, int $stockId) : void { $productTypes = $this->getProductTypesBySkus->execute(array_keys($items)); foreach ($items as $sku => $qty) { - if (false === $this->isSourceItemsAllowedForProductType->execute($productTypes[$sku])) { + if (false === $this->isSourceItemsAllowedForProductType->execute($productTypes[$sku]) + && $productTypes[$sku] != Configurable::TYPE_CODE + ) { $defaultStockId = $this->defaultStockProvider->getId(); if ($defaultStockId !== $stockId) { throw new LocalizedException( - __('Product type is not supported on Default Stock.') + __('Product type is not supported on not Default Stock.') ); } continue; diff --git a/app/code/Magento/InventorySales/Model/IsProductSalableForRequestedQtyCondition/IsSalableWithReservationsCondition.php b/app/code/Magento/InventorySales/Model/IsProductSalableForRequestedQtyCondition/IsSalableWithReservationsCondition.php index 13b95e6fc977..1a1af1cdecb6 100644 --- a/app/code/Magento/InventorySales/Model/IsProductSalableForRequestedQtyCondition/IsSalableWithReservationsCondition.php +++ b/app/code/Magento/InventorySales/Model/IsProductSalableForRequestedQtyCondition/IsSalableWithReservationsCondition.php @@ -7,6 +7,8 @@ namespace Magento\InventorySales\Model\IsProductSalableForRequestedQtyCondition; +use Magento\InventoryCatalog\Model\GetProductTypesBySkusInterface; +use Magento\InventoryConfiguration\Model\IsSourceItemsAllowedForProductType; use Magento\InventoryReservations\Model\GetReservationsQuantityInterface; use Magento\InventorySalesApi\Api\IsProductSalableForRequestedQtyInterface; use Magento\InventorySales\Model\GetStockItemDataInterface; @@ -46,25 +48,41 @@ class IsSalableWithReservationsCondition implements IsProductSalableForRequested */ private $productSalableResultFactory; + /** + * @var IsSourceItemsAllowedForProductType + */ + private $isSourceItemsAllowedForProductType; + + /** + * @var GetProductTypesBySkusInterface + */ + private $getProductTypesBySkus; + /** * @param GetStockItemDataInterface $getStockItemData * @param GetReservationsQuantityInterface $getReservationsQuantity * @param GetStockItemConfigurationInterface $getStockItemConfiguration * @param ProductSalabilityErrorInterfaceFactory $productSalabilityErrorFactory * @param ProductSalableResultInterfaceFactory $productSalableResultFactory + * @param IsSourceItemsAllowedForProductType $isSourceItemsAllowedForProductType + * @param GetProductTypesBySkusInterface $getProductTypesBySkus */ public function __construct( GetStockItemDataInterface $getStockItemData, GetReservationsQuantityInterface $getReservationsQuantity, GetStockItemConfigurationInterface $getStockItemConfiguration, ProductSalabilityErrorInterfaceFactory $productSalabilityErrorFactory, - ProductSalableResultInterfaceFactory $productSalableResultFactory + ProductSalableResultInterfaceFactory $productSalableResultFactory, + IsSourceItemsAllowedForProductType $isSourceItemsAllowedForProductType, + GetProductTypesBySkusInterface $getProductTypesBySkus ) { $this->getStockItemData = $getStockItemData; $this->getReservationsQuantity = $getReservationsQuantity; $this->getStockItemConfiguration = $getStockItemConfiguration; $this->productSalabilityErrorFactory = $productSalabilityErrorFactory; $this->productSalableResultFactory = $productSalableResultFactory; + $this->isSourceItemsAllowedForProductType = $isSourceItemsAllowedForProductType; + $this->getProductTypesBySkus = $getProductTypesBySkus; } /** @@ -84,21 +102,31 @@ public function execute(string $sku, int $stockId, float $requestedQty): Product return $this->productSalableResultFactory->create(['errors' => $errors]); } - $qtyWithReservation = $stockItemData[GetStockItemDataInterface::QUANTITY] + - $this->getReservationsQuantity->execute($sku, $stockId); - /** @var StockItemConfigurationInterface $stockItemConfiguration */ - $stockItemConfiguration = $this->getStockItemConfiguration->execute($sku, $stockId); - $qtyLeftInStock = $qtyWithReservation - $stockItemConfiguration->getMinQty() - $requestedQty; - $isEnoughQty = (bool)$stockItemData[GetStockItemDataInterface::IS_SALABLE] && $qtyLeftInStock >= 0; - if (!$isEnoughQty) { + $productType = $this->getProductTypesBySkus->execute([$sku])[$sku]; + + if (true === $this->isSourceItemsAllowedForProductType->execute($productType)) { + $qtyWithReservation = $stockItemData[GetStockItemDataInterface::QUANTITY] + + $this->getReservationsQuantity->execute($sku, $stockId); + + /** @var StockItemConfigurationInterface $stockItemConfiguration */ + $stockItemConfiguration = $this->getStockItemConfiguration->execute($sku, $stockId); + $qtyLeftInStock = $qtyWithReservation - $stockItemConfiguration->getMinQty() - $requestedQty; + $isSalable = (bool)$stockItemData[GetStockItemDataInterface::IS_SALABLE]; + $isSalableForRequestedQty = $isSalable && $qtyLeftInStock >= 0; + } else { + $isSalableForRequestedQty = (bool)$stockItemData[GetStockItemDataInterface::IS_SALABLE]; + } + + $errors = []; + if (!$isSalableForRequestedQty) { $errors = [ $this->productSalabilityErrorFactory->create([ 'code' => 'is_salable_with_reservations-not_enough_qty', 'message' => __('The requested qty is not available') ]) ]; - return $this->productSalableResultFactory->create(['errors' => $errors]); } - return $this->productSalableResultFactory->create(['errors' => []]); + + return $this->productSalableResultFactory->create(['errors' => $errors]); } } diff --git a/app/code/Magento/InventorySales/composer.json b/app/code/Magento/InventorySales/composer.json index d5ae6cbf74fd..26b1defd77ee 100644 --- a/app/code/Magento/InventorySales/composer.json +++ b/app/code/Magento/InventorySales/composer.json @@ -6,6 +6,7 @@ "magento/framework": "*", "magento/module-catalog-inventory": "*", "magento/module-catalog": "*", + "magento/module-configurable-product": "*", "magento/module-inventory-api": "*", "magento/module-inventory-catalog": "*", "magento/module-inventory-configuration": "*",