15
15
use Magento \Quote \Model \MaskedQuoteIdToQuoteIdInterface ;
16
16
use Magento \Quote \Model \Quote ;
17
17
use Magento \Framework \Message \MessageInterface ;
18
- use Magento \Quote \Model \Quote \Item ;
19
- use Magento \Quote \Model \QuoteFactory ;
20
18
21
19
/**
22
20
* Unified approach to add products to the Shopping Cart.
@@ -67,30 +65,22 @@ class AddProductsToCart
67
65
*/
68
66
private $ requestBuilder ;
69
67
70
- /**
71
- * @var QuoteFactory
72
- */
73
- private $ quoteFactory ;
74
-
75
68
/**
76
69
* @param ProductRepositoryInterface $productRepository
77
70
* @param CartRepositoryInterface $cartRepository
78
71
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
79
72
* @param BuyRequestBuilder $requestBuilder
80
- * @param QuoteFactory $quoteFactory
81
73
*/
82
74
public function __construct (
83
75
ProductRepositoryInterface $ productRepository ,
84
76
CartRepositoryInterface $ cartRepository ,
85
77
MaskedQuoteIdToQuoteIdInterface $ maskedQuoteIdToQuoteId ,
86
- BuyRequestBuilder $ requestBuilder ,
87
- QuoteFactory $ quoteFactory
78
+ BuyRequestBuilder $ requestBuilder
88
79
) {
89
80
$ this ->productRepository = $ productRepository ;
90
81
$ this ->cartRepository = $ cartRepository ;
91
82
$ this ->maskedQuoteIdToQuoteId = $ maskedQuoteIdToQuoteId ;
92
83
$ this ->requestBuilder = $ requestBuilder ;
93
- $ this ->quoteFactory = $ quoteFactory ;
94
84
}
95
85
96
86
/**
@@ -115,14 +105,25 @@ public function execute(string $maskedCartId, array $cartItems): AddProductsToCa
115
105
}
116
106
}
117
107
118
- foreach ($ cartItems as $ cartItemPosition => $ cartItem ) {
119
- $ errors = $ this ->addItemToCart ($ cart , $ cartItem , $ cartItemPosition );
120
- if ($ errors ) {
121
- array_push ($ allErrors , ...$ errors );
108
+ $ failedCartItems = $ this ->addItemsToCart ($ cart , $ cartItems );
109
+ $ saveCart = true ;
110
+ if (count ($ failedCartItems ) !== count ($ cartItems )) {
111
+ /* Revert changes introduced by add to cart processes in case of an error */
112
+ $ cart ->getItemsCollection ()->clear ();
113
+ $ newFailedCartItems = $ this ->addItemsToCart ($ cart , array_diff_key ($ cartItems , $ failedCartItems ));
114
+ $ saveCart = empty ($ newFailedCartItems );
115
+ $ failedCartItems += $ newFailedCartItems ;
116
+ }
117
+
118
+ foreach (array_keys ($ cartItems ) as $ cartItemPosition ) {
119
+ if (isset ($ failedCartItems [$ cartItemPosition ])) {
120
+ array_push ($ allErrors , ...$ failedCartItems [$ cartItemPosition ]);
122
121
}
123
122
}
124
123
125
- $ this ->cartRepository ->save ($ cart );
124
+ if ($ saveCart ) {
125
+ $ this ->cartRepository ->save ($ cart );
126
+ }
126
127
127
128
if (count ($ allErrors ) !== 0 ) {
128
129
/* Revert changes introduced by add to cart processes in case of an error */
@@ -132,6 +133,27 @@ public function execute(string $maskedCartId, array $cartItems): AddProductsToCa
132
133
return $ this ->prepareErrorOutput ($ cart , $ allErrors );
133
134
}
134
135
136
+ /**
137
+ * Add cart items to cart
138
+ *
139
+ * @param Quote $cart
140
+ * @param array $cartItems
141
+ * @return array
142
+ */
143
+ public function addItemsToCart (Quote $ cart , array $ cartItems ): array
144
+ {
145
+ $ failedCartItems = [];
146
+
147
+ foreach ($ cartItems as $ cartItemPosition => $ cartItem ) {
148
+ $ errors = $ this ->addItemToCart ($ cart , $ cartItem , $ cartItemPosition );
149
+ if ($ errors ) {
150
+ $ failedCartItems [$ cartItemPosition ] = $ errors ;
151
+ }
152
+ }
153
+
154
+ return $ failedCartItems ;
155
+ }
156
+
135
157
/**
136
158
* Adds a particular item to the shopping cart
137
159
*
@@ -146,8 +168,6 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
146
168
$ errors = [];
147
169
$ result = null ;
148
170
$ product = null ;
149
- $ tempCart = $ this ->cloneQuote ($ cart );
150
- $ tempCart ->setHasError (false );
151
171
152
172
if ($ cartItem ->getQuantity () <= 0 ) {
153
173
$ errors [] = $ this ->createError (__ ('The product quantity should be greater than 0 ' )->render ());
@@ -163,7 +183,7 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
163
183
164
184
if ($ product !== null ) {
165
185
try {
166
- $ result = $ tempCart ->addProduct ($ product , $ this ->requestBuilder ->build ($ cartItem ));
186
+ $ result = $ cart ->addProduct ($ product , $ this ->requestBuilder ->build ($ cartItem ));
167
187
} catch (\Throwable $ e ) {
168
188
$ errors [] = $ this ->createError (
169
189
__ ($ e ->getMessage ())->render (),
@@ -179,10 +199,6 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
179
199
}
180
200
}
181
201
182
- if (empty ($ errors )) {
183
- $ this ->addQuoteItem ($ cart , $ result );
184
- }
185
-
186
202
return $ errors ;
187
203
}
188
204
@@ -236,77 +252,4 @@ private function prepareErrorOutput(Quote $cart, array $errors = []): AddProduct
236
252
237
253
return $ output ;
238
254
}
239
-
240
- /**
241
- * Add quote item from temporary quote to real quote
242
- *
243
- * @param Quote $quote
244
- * @param Item $quoteItem
245
- * @return void
246
- */
247
- private function addQuoteItem (Quote $ quote , Item $ quoteItem ): void
248
- {
249
- if ($ quoteItem ->getOriginalItem ()) {
250
- $ quote ->deleteItem ($ quoteItem ->getOriginalItem ());
251
- $ quoteItem ->unsOriginalItem ();
252
- }
253
-
254
- $ quoteItem ->setQuote ($ quote );
255
- $ quote ->addItem ($ quoteItem );
256
- if ($ quoteItem ->getHasChildren ()) {
257
- foreach ($ quoteItem ->getChildren () as $ childQuoteItem ) {
258
- $ childQuoteItem ->setQuote ($ quote );
259
- $ quote ->addItem ($ childQuoteItem );
260
- }
261
- }
262
-
263
- $ parentQuoteItem = $ quoteItem ->getParentItem ();
264
- if ($ parentQuoteItem ) {
265
- $ parentQuoteItem ->setQuote ($ quote );
266
- $ quote ->addItem ($ parentQuoteItem );
267
- }
268
- }
269
-
270
- /**
271
- * Create a clone quote.
272
- *
273
- * @param Quote $quote
274
- * @return Quote
275
- */
276
- private function cloneQuote (Quote $ quote )
277
- {
278
- // copy data to temporary quote
279
- /** @var $temporaryQuote \Magento\Quote\Model\Quote */
280
- $ temporaryQuote = $ this ->quoteFactory ->create ();
281
- $ temporaryQuote ->setData ($ quote ->getData ());
282
- $ temporaryQuote ->setId (null );//as it is clone, we need to flush ids
283
- $ temporaryQuote ->setStore ($ quote ->getStore ())->setIsSuperMode ($ quote ->getIsSuperMode ());
284
-
285
- /** @var Item $quoteItem */
286
- foreach ($ quote ->getAllItems () as $ quoteItem ) {
287
- $ temporaryItem = clone $ quoteItem ;
288
- $ temporaryItem ->setQuote ($ temporaryQuote );
289
- $ temporaryQuote ->addItem ($ temporaryItem );
290
- $ quoteItem ->setClonnedItem ($ temporaryItem );
291
- }
292
- /** @var Item $quoteItem */
293
- foreach ($ quote ->getAllItems () as $ quoteItem ) {
294
- $ temporaryItem = $ quoteItem ->getClonnedItem ();
295
- //Check for parent item
296
- $ parentItem = null ;
297
- if ($ quoteItem ->getParentItem ()) {
298
- $ parentItem = $ quoteItem ->getParentItem ();
299
- $ temporaryItem ->setParentProductId (null );
300
- } elseif ($ quoteItem ->getParentProductId ()) {
301
- $ parentItem = $ quote ->getItemById ($ quoteItem ->getParentProductId ());
302
- }
303
- if ($ parentItem && $ parentItem ->getClonnedItem ()) {
304
- $ temporaryItem ->setParentItem ($ parentItem ->getClonnedItem ());
305
- }
306
- $ quoteItem ->unsClonnedItem ();
307
- $ temporaryItem ->setOriginalItem ($ quoteItem );
308
- }
309
-
310
- return $ temporaryQuote ;
311
- }
312
255
}
0 commit comments