11<?php
22/**
3- * Copyright 2019 Adobe
4- * All Rights Reserved .
3+ * Copyright © Magento, Inc. All rights reserved.
4+ * See COPYING.txt for license details .
55 */
66declare (strict_types=1 );
77
88namespace Magento \QuoteGraphQl \Model \Cart \MergeCarts ;
99
10- use Magento \Catalog \Api \Data \ProductInterface ;
11- use Magento \Catalog \Api \ProductRepositoryInterface ;
10+
1211use Magento \CatalogInventory \Api \StockRegistryInterface ;
13- use Magento \Checkout \Model \Config ;
1412use Magento \Framework \Exception \CouldNotSaveException ;
1513use Magento \Framework \Exception \NoSuchEntityException ;
1614use Magento \Quote \Api \CartItemRepositoryInterface ;
1715use Magento \Quote \Api \Data \CartInterface ;
1816use Magento \Quote \Api \Data \CartItemInterface ;
19- use Magento \Quote \Model \Quote \Item ;
20- use Psr \Log \LoggerInterface ;
2117
2218class CartQuantityValidator implements CartQuantityValidatorInterface
2319{
2420 /**
25- * @var array
21+ * @var CartItemRepositoryInterface
2622 */
27- private array $ cumulativeQty = [];
23+ private $ cartItemRepository ;
24+
25+ /**
26+ * @var StockRegistryInterface
27+ */
28+ private $ stockRegistry ;
2829
2930 /**
30- * CartQuantityValidator Constructor
31- *
3231 * @param CartItemRepositoryInterface $cartItemRepository
3332 * @param StockRegistryInterface $stockRegistry
34- * @param Config $config
35- * @param ProductRepositoryInterface $productRepository
36- * @param LoggerInterface $logger
3733 */
3834 public function __construct (
39- private readonly CartItemRepositoryInterface $ cartItemRepository ,
40- private readonly StockRegistryInterface $ stockRegistry ,
41- private readonly Config $ config ,
42- private readonly ProductRepositoryInterface $ productRepository ,
43- private readonly LoggerInterface $ logger
35+ CartItemRepositoryInterface $ cartItemRepository ,
36+ StockRegistryInterface $ stockRegistry
4437 ) {
38+ $ this ->cartItemRepository = $ cartItemRepository ;
39+ $ this ->stockRegistry = $ stockRegistry ;
4540 }
4641
4742 /**
@@ -50,171 +45,32 @@ public function __construct(
5045 * @param CartInterface $customerCart
5146 * @param CartInterface $guestCart
5247 * @return bool
53- * @throws NoSuchEntityException
5448 */
5549 public function validateFinalCartQuantities (CartInterface $ customerCart , CartInterface $ guestCart ): bool
5650 {
5751 $ modified = false ;
58- $ this ->cumulativeQty = [];
59-
52+ /** @var CartItemInterface $guestCartItem */
6053 foreach ($ guestCart ->getAllVisibleItems () as $ guestCartItem ) {
61- foreach ($ customerCart ->getAllVisibleItems () as $ customerCartItem ) {
62- if (!$ customerCartItem ->compare ($ guestCartItem )) {
63- continue ;
64- }
65-
66- if ($ this ->config ->getCartMergePreference () === Config::CART_PREFERENCE_CUSTOMER ) {
67- $ this ->safeDeleteCartItem ((int ) $ guestCart ->getId (), (int ) $ guestCartItem ->getItemId ());
68- $ modified = true ;
69- continue ;
70- }
71-
72- $ sku = $ this ->getSkuFromItem ($ customerCartItem );
73- $ product = $ this ->getProduct ((int ) $ customerCartItem ->getProduct ()->getId ());
74- $ isAvailable = $ customerCartItem ->getChildren ()
75- ? $ this ->isCompositeProductQtyValid ($ guestCartItem , $ customerCartItem )
76- : $ this ->isProductQtyValid ($ product , $ sku , $ guestCartItem ->getQty (), $ customerCartItem ->getQty ());
77-
78- if ($ this ->config ->getCartMergePreference () === Config::CART_PREFERENCE_GUEST ) {
79- $ this ->safeDeleteCartItem ((int ) $ customerCart ->getId (), (int ) $ customerCartItem ->getItemId ());
80- $ modified = true ;
81- }
82-
83- if (!$ isAvailable ) {
84- $ this ->safeDeleteCartItem ((int ) $ guestCart ->getId (), (int ) $ guestCartItem ->getItemId ());
85- $ modified = true ;
54+ foreach ($ customerCart ->getAllItems () as $ customerCartItem ) {
55+ if ($ customerCartItem ->compare ($ guestCartItem )) {
56+ $ product = $ customerCartItem ->getProduct ();
57+ $ stockCurrentQty = $ this ->stockRegistry ->getStockStatus (
58+ $ product ->getId (),
59+ $ product ->getStore ()->getWebsiteId ()
60+ )->getQty ();
61+ if ($ stockCurrentQty < $ guestCartItem ->getQty () + $ customerCartItem ->getQty ()) {
62+ try {
63+ $ this ->cartItemRepository ->deleteById ($ guestCart ->getId (), $ guestCartItem ->getItemId ());
64+ $ modified = true ;
65+ } catch (NoSuchEntityException $ e ) {
66+ continue ;
67+ } catch (CouldNotSaveException $ e ) {
68+ continue ;
69+ }
70+ }
8671 }
8772 }
8873 }
89-
9074 return $ modified ;
9175 }
92-
93- /**
94- * Get SKU from Cart Item
95- *
96- * @param CartItemInterface $item
97- * @return string
98- * @throws NoSuchEntityException
99- */
100- private function getSkuFromItem (CartItemInterface $ item ): string
101- {
102- return $ item ->getProduct ()->getOptions ()
103- ? $ this ->getProduct ((int ) $ item ->getProduct ()->getId ())->getSku ()
104- : $ item ->getProduct ()->getSku ();
105- }
106-
107- /**
108- * Get current cart item quantity based on merge preference
109- *
110- * @param float $guestQty
111- * @param float $customerQty
112- * @return float
113- */
114- private function getCurrentCartItemQty (float $ guestQty , float $ customerQty ): float
115- {
116- return match ($ this ->config ->getCartMergePreference ()) {
117- Config::CART_PREFERENCE_CUSTOMER => $ customerQty ,
118- Config::CART_PREFERENCE_GUEST => $ guestQty ,
119- default => $ guestQty + $ customerQty
120- };
121- }
122-
123- /**
124- * Validate product stock availability
125- *
126- * @param ProductInterface $product
127- * @param string $sku
128- * @param float $guestQty
129- * @param float $customerQty
130- * @return bool
131- */
132- private function isProductQtyValid (
133- ProductInterface $ product ,
134- string $ sku ,
135- float $ guestQty ,
136- float $ customerQty
137- ): bool {
138- $ salableQty = $ this ->stockRegistry ->getStockStatus (
139- $ product ->getId (),
140- $ product ->getStore ()->getWebsiteId ()
141- )->getQty ();
142-
143- $ this ->cumulativeQty [$ sku ] ??= 0 ;
144- $ this ->cumulativeQty [$ sku ] += $ this ->getCurrentCartItemQty ($ guestQty , $ customerQty );
145-
146- return $ salableQty >= $ this ->cumulativeQty [$ sku ];
147- }
148-
149- /**
150- * Validate composite product quantities
151- *
152- * @param Item $guestCartItem
153- * @param Item $customerCartItem
154- * @return bool
155- * @throws NoSuchEntityException
156- */
157- private function isCompositeProductQtyValid (
158- Item $ guestCartItem ,
159- Item $ customerCartItem
160- ): bool {
161- $ guestChildItems = $ this ->retrieveChildItems ($ guestCartItem );
162- foreach ($ customerCartItem ->getChildren () as $ customerChildItem ) {
163- $ childProduct = $ customerChildItem ->getProduct ()->getOptions ()
164- ? $ this ->getProduct ((int ) $ customerChildItem ->getProduct ()->getId ())
165- : $ customerChildItem ->getProduct ();
166- $ sku = $ childProduct ->getSku ();
167- $ customerItemQty = $ customerCartItem ->getQty () * $ customerChildItem ->getQty ();
168- $ guestItemQty = $ guestCartItem ->getQty () * $ guestChildItems [$ sku ]->getQty ();
169-
170- if (!$ this ->isProductQtyValid ($ childProduct , $ sku , $ guestItemQty , $ customerItemQty )) {
171- return false ;
172- }
173- }
174-
175- return true ;
176- }
177-
178- /**
179- * Get product by ID
180- *
181- * @param int $productId
182- * @return ProductInterface
183- * @throws NoSuchEntityException
184- */
185- private function getProduct (int $ productId ): ProductInterface
186- {
187- return $ this ->productRepository ->getById ($ productId );
188- }
189-
190- /**
191- * Retrieve child items from a quote item
192- *
193- * @param Item $quoteItem
194- * @return Item[]
195- */
196- private function retrieveChildItems (Item $ quoteItem ): array
197- {
198- $ childItems = [];
199- foreach ($ quoteItem ->getChildren () as $ childItem ) {
200- $ childItems [$ childItem ->getProduct ()->getSku ()] = $ childItem ;
201- }
202- return $ childItems ;
203- }
204-
205- /**
206- * Safely delete a cart item by ID
207- *
208- * @param int $cartId
209- * @param int $itemId
210- * @return void
211- */
212- private function safeDeleteCartItem (int $ cartId , int $ itemId ): void
213- {
214- try {
215- $ this ->cartItemRepository ->deleteById ($ cartId , $ itemId );
216- } catch (NoSuchEntityException |CouldNotSaveException $ e ) {
217- $ this ->logger ->error ($ e );
218- }
219- }
22076}
0 commit comments