Skip to content

Commit 6710bab

Browse files
committed
ACP2E-368: Issue when adding multiple items in addProductsToCart graphQL mutation
1 parent acf4d8e commit 6710bab

File tree

3 files changed

+45
-106
lines changed

3 files changed

+45
-106
lines changed

app/code/Magento/Quote/Model/Cart/AddProductsToCart.php

Lines changed: 39 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
1616
use Magento\Quote\Model\Quote;
1717
use Magento\Framework\Message\MessageInterface;
18-
use Magento\Quote\Model\Quote\Item;
19-
use Magento\Quote\Model\QuoteFactory;
2018

2119
/**
2220
* Unified approach to add products to the Shopping Cart.
@@ -67,30 +65,22 @@ class AddProductsToCart
6765
*/
6866
private $requestBuilder;
6967

70-
/**
71-
* @var QuoteFactory
72-
*/
73-
private $quoteFactory;
74-
7568
/**
7669
* @param ProductRepositoryInterface $productRepository
7770
* @param CartRepositoryInterface $cartRepository
7871
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
7972
* @param BuyRequestBuilder $requestBuilder
80-
* @param QuoteFactory $quoteFactory
8173
*/
8274
public function __construct(
8375
ProductRepositoryInterface $productRepository,
8476
CartRepositoryInterface $cartRepository,
8577
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
86-
BuyRequestBuilder $requestBuilder,
87-
QuoteFactory $quoteFactory
78+
BuyRequestBuilder $requestBuilder
8879
) {
8980
$this->productRepository = $productRepository;
9081
$this->cartRepository = $cartRepository;
9182
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
9283
$this->requestBuilder = $requestBuilder;
93-
$this->quoteFactory = $quoteFactory;
9484
}
9585

9686
/**
@@ -115,14 +105,25 @@ public function execute(string $maskedCartId, array $cartItems): AddProductsToCa
115105
}
116106
}
117107

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]);
122121
}
123122
}
124123

125-
$this->cartRepository->save($cart);
124+
if ($saveCart) {
125+
$this->cartRepository->save($cart);
126+
}
126127

127128
if (count($allErrors) !== 0) {
128129
/* 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
132133
return $this->prepareErrorOutput($cart, $allErrors);
133134
}
134135

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+
135157
/**
136158
* Adds a particular item to the shopping cart
137159
*
@@ -146,8 +168,6 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
146168
$errors = [];
147169
$result = null;
148170
$product = null;
149-
$tempCart = $this->cloneQuote($cart);
150-
$tempCart->setHasError(false);
151171

152172
if ($cartItem->getQuantity() <= 0) {
153173
$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
163183

164184
if ($product !== null) {
165185
try {
166-
$result = $tempCart->addProduct($product, $this->requestBuilder->build($cartItem));
186+
$result = $cart->addProduct($product, $this->requestBuilder->build($cartItem));
167187
} catch (\Throwable $e) {
168188
$errors[] = $this->createError(
169189
__($e->getMessage())->render(),
@@ -179,10 +199,6 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt
179199
}
180200
}
181201

182-
if (empty($errors)) {
183-
$this->addQuoteItem($cart, $result);
184-
}
185-
186202
return $errors;
187203
}
188204

@@ -236,77 +252,4 @@ private function prepareErrorOutput(Quote $cart, array $errors = []): AddProduct
236252

237253
return $output;
238254
}
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-
}
312255
}

app/code/Magento/Quote/Model/Quote/Item/Compare.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ protected function getOptionValues($value)
6868
*/
6969
public function compare(Item $target, Item $compared)
7070
{
71-
if ($target === $compared) {
72-
return true;
73-
}
74-
7571
if ($target->getProductId() != $compared->getProductId()) {
7672
return false;
7773
}

dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/AddSimpleProductToCartSingleMutationTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,17 +316,17 @@ public function testAddMultipleProductsToNotEmptyCart(): void
316316
self::assertCount(3, $result['cart']['items']);
317317

318318
$cartItem = $result['cart']['items'][0];
319-
self::assertEquals($product2->getSku(), $cartItem['product']['sku']);
320-
self::assertEquals(1, $cartItem['quantity']);
321-
self::assertEquals(10, $cartItem['prices']['price']['value']);
322-
self::assertEquals(10, $cartItem['prices']['row_total']['value']);
323-
324-
$cartItem = $result['cart']['items'][1];
325319
self::assertEquals($product1->getSku(), $cartItem['product']['sku']);
326320
self::assertEquals(2, $cartItem['quantity']);
327321
self::assertEquals(10, $cartItem['prices']['price']['value']);
328322
self::assertEquals(20, $cartItem['prices']['row_total']['value']);
329323

324+
$cartItem = $result['cart']['items'][1];
325+
self::assertEquals($product2->getSku(), $cartItem['product']['sku']);
326+
self::assertEquals(1, $cartItem['quantity']);
327+
self::assertEquals(10, $cartItem['prices']['price']['value']);
328+
self::assertEquals(10, $cartItem['prices']['row_total']['value']);
329+
330330
$cartItem = $result['cart']['items'][2];
331331
self::assertEquals($product3->getSku(), $cartItem['product']['sku']);
332332
self::assertEquals(1, $cartItem['quantity']);

0 commit comments

Comments
 (0)