8
8
namespace Magento \QuoteGraphQl \Model \CartItem ;
9
9
10
10
use Magento \Catalog \Api \Data \ProductInterface ;
11
- use Magento \CatalogInventory \Model \StockState ;
12
11
use Magento \Catalog \Api \ProductRepositoryInterface ;
12
+ use Magento \CatalogInventory \Api \StockConfigurationInterface ;
13
+ use Magento \CatalogInventory \Api \StockRegistryInterface ;
14
+ use Magento \CatalogInventory \Model \Configuration ;
15
+ use Magento \CatalogInventory \Model \StockState ;
16
+ use Magento \Framework \App \Config \ScopeConfigInterface ;
13
17
use Magento \Framework \Exception \NoSuchEntityException ;
14
18
use Magento \Quote \Model \Quote \Item ;
15
- use Magento \CatalogInventory \ Api \ StockConfigurationInterface ;
19
+ use Magento \Store \ Model \ ScopeInterface ;
16
20
17
21
/**
18
22
* Product Stock class to check availability of product
@@ -35,11 +39,15 @@ class ProductStock
35
39
* @param ProductRepositoryInterface $productRepositoryInterface
36
40
* @param StockState $stockState
37
41
* @param StockConfigurationInterface $stockConfiguration
42
+ * @param ScopeConfigInterface $scopeConfig
43
+ * @param StockRegistryInterface $stockRegistry
38
44
*/
39
45
public function __construct (
40
46
private readonly ProductRepositoryInterface $ productRepositoryInterface ,
41
47
private readonly StockState $ stockState ,
42
- private readonly StockConfigurationInterface $ stockConfiguration
48
+ private readonly StockConfigurationInterface $ stockConfiguration ,
49
+ private readonly ScopeConfigInterface $ scopeConfig ,
50
+ private readonly StockRegistryInterface $ stockRegistry
43
51
) {
44
52
}
45
53
@@ -74,6 +82,7 @@ public function isProductAvailable(Item $cartItem): bool
74
82
* @param int $previousQty
75
83
* @param int|float $requestedQty
76
84
* @return bool
85
+ * @throws NoSuchEntityException
77
86
*/
78
87
public function isStockAvailableBundle (Item $ cartItem , int $ previousQty , $ requestedQty ): bool
79
88
{
@@ -188,4 +197,66 @@ private function getLowestStockValueOfBundleProduct(Item $cartItem): float
188
197
189
198
return min ($ bundleStock );
190
199
}
200
+
201
+ /**
202
+ * Returns the lowest stock value of bundle product
203
+ *
204
+ * @param Item $cartItem
205
+ * @param float $thresholdQty
206
+ * @return float
207
+ */
208
+ private function getLowestSaleableQtyOfBundleProduct (Item $ cartItem , float $ thresholdQty ): float
209
+ {
210
+ $ bundleStock = [];
211
+ foreach ($ cartItem ->getQtyOptions () as $ qtyOption ) {
212
+ $ bundleStock [] = $ this ->getSaleableQty ($ qtyOption ->getProduct (), $ thresholdQty );
213
+ }
214
+ return $ bundleStock ? (float )min ($ bundleStock ) : 0.0 ;
215
+ }
216
+
217
+ /**
218
+ * Returns the cart item's saleable qty value
219
+ *
220
+ * @param Item $cartItem
221
+ * @return float
222
+ * @throws NoSuchEntityException
223
+ */
224
+ public function getProductSaleableQty (Item $ cartItem ): float
225
+ {
226
+ $ thresholdQty = (float )$ this ->scopeConfig ->getValue (
227
+ Configuration::XML_PATH_STOCK_THRESHOLD_QTY ,
228
+ ScopeInterface::SCOPE_STORE
229
+ );
230
+
231
+ if ($ thresholdQty === 0.0 ) {
232
+ return $ this ->getProductAvailableStock ($ cartItem );
233
+ }
234
+
235
+ if ($ cartItem ->getProductType () === self ::PRODUCT_TYPE_BUNDLE ) {
236
+ return $ this ->getLowestSaleableQtyOfBundleProduct ($ cartItem , $ thresholdQty );
237
+ }
238
+
239
+ $ variantProduct = $ this ->getVariantProduct ($ cartItem );
240
+ if ($ variantProduct !== null ) {
241
+ return $ this ->getSaleableQty ($ variantProduct , $ thresholdQty );
242
+ }
243
+
244
+ return $ this ->getSaleableQty ($ cartItem ->getProduct (), $ thresholdQty );
245
+ }
246
+
247
+ /**
248
+ * Get product saleable qty when "Catalog > Inventory > Stock Options > Only X left Threshold" is greater than 0
249
+ *
250
+ * @param ProductInterface $product
251
+ * @param float $thresholdQty
252
+ * @return float
253
+ */
254
+ private function getSaleableQty (ProductInterface $ product , float $ thresholdQty ): float
255
+ {
256
+ $ stockItem = $ this ->stockRegistry ->getStockItem ($ product ->getId ());
257
+ $ stockStatus = $ this ->stockRegistry ->getStockStatus ($ product ->getId (), $ product ->getStore ()->getWebsiteId ());
258
+ $ stockCurrentQty = $ stockStatus ->getQty ();
259
+ $ stockLeft = $ stockCurrentQty - $ stockItem ->getMinQty ();
260
+ return ($ stockCurrentQty >= 0 && $ stockLeft <= $ thresholdQty ) ? (float )$ stockCurrentQty : 0.0 ;
261
+ }
191
262
}
0 commit comments