Skip to content

Commit 94270e3

Browse files
committed
Merge branch '2.4-develop' into T4-PR-07-02-2024
2 parents 4419df7 + 140433c commit 94270e3

File tree

4 files changed

+247
-5
lines changed

4 files changed

+247
-5
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class ProductReader implements ProductReaderInterface
2525
/**
2626
* @var ProductInterface[]
2727
*/
28-
private $productsBySku;
28+
private array $productsBySku;
2929

3030
/**
3131
* @var Config
@@ -65,7 +65,7 @@ public function loadProducts(array $skus, int $storeId): void
6565
$this->productCollection->addOptionsToResult();
6666
$this->productCollection->load();
6767
foreach ($this->productCollection->getItems() as $productItem) {
68-
$this->productsBySku[$productItem->getData(ProductInterface::SKU)] = $productItem;
68+
$this->productsBySku[strtolower($productItem->getData(ProductInterface::SKU))] = $productItem;
6969
}
7070
}
7171

@@ -74,6 +74,6 @@ public function loadProducts(array $skus, int $storeId): void
7474
*/
7575
public function getProductBySku(string $sku) : ?ProductInterface
7676
{
77-
return $this->productsBySku[$sku] ?? null;
77+
return $this->productsBySku[strtolower($sku)] ?? null;
7878
}
7979
}

app/code/Magento/QuoteGraphQl/Model/Resolver/UpdateCartItems.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
8787

8888
try {
8989
$this->updateCartItems->processCartItems($cart, $cartItems);
90-
$this->cartRepository->save($cart);
90+
$updatedCart = $this->getCartForUser->execute($maskedCartId, $context->getUserId(), $storeId);
91+
$this->cartRepository->save($updatedCart);
9192
} catch (NoSuchEntityException $e) {
9293
throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e);
9394
} catch (LocalizedException $e) {
@@ -96,7 +97,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
9697

9798
return [
9899
'cart' => [
99-
'model' => $cart,
100+
'model' => $updatedCart,
100101
],
101102
];
102103
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* ADOBE CONFIDENTIAL
5+
* ___________________
6+
*
7+
* Copyright 2024 Adobe
8+
* All Rights Reserved.
9+
*
10+
* NOTICE: All information contained herein is, and remains
11+
* the property of Adobe and its suppliers, if any. The intellectual
12+
* and technical concepts contained herein are proprietary to Adobe
13+
* and its suppliers and are protected by all applicable intellectual
14+
* property laws, including trade secret and copyright laws.
15+
* Dissemination of this information or reproduction of this material
16+
* is strictly forbidden unless prior written permission is obtained
17+
* from Adobe.
18+
* ************************************************************************
19+
*/
20+
declare(strict_types=1);
21+
22+
namespace Magento\GraphQl\Quote;
23+
24+
use Exception;
25+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
26+
use Magento\Framework\Exception\NoSuchEntityException;
27+
use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
28+
use Magento\Quote\Test\Fixture\GuestCart as GuestCartFixture;
29+
use Magento\TestFramework\Fixture\DataFixture;
30+
use Magento\TestFramework\Fixture\DataFixtureStorage;
31+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
32+
use Magento\TestFramework\Helper\Bootstrap;
33+
use Magento\TestFramework\TestCase\GraphQlAbstract;
34+
35+
/**
36+
* Get add to cart through GraphQl query and variables
37+
*/
38+
class AddProductsToCartTest extends GraphQlAbstract
39+
{
40+
/**
41+
* @var QuoteIdToMaskedQuoteIdInterface
42+
*/
43+
private $quoteIdToMaskedQuoteId;
44+
45+
/**
46+
* @var DataFixtureStorage
47+
*/
48+
private $fixtures;
49+
50+
/**
51+
* @inheritdoc
52+
*/
53+
protected function setUp(): void
54+
{
55+
$this->quoteIdToMaskedQuoteId = Bootstrap::getObjectManager()->get(QuoteIdToMaskedQuoteIdInterface::class);
56+
$this->fixtures = Bootstrap::getObjectManager()->get(DataFixtureStorageManager::class)->getStorage();
57+
}
58+
59+
/**
60+
* Test addProductsToCart mutation by passing SKU Upper & Lower case
61+
*
62+
* @param string $sku
63+
* @dataProvider skuDataProvider
64+
* @throws NoSuchEntityException
65+
* @throws Exception
66+
*/
67+
#[
68+
DataFixture(ProductFixture::class, ['sku' => 'Upper_And_Lower_Test_Prod']),
69+
DataFixture(GuestCartFixture::class, as: 'cart'),
70+
]
71+
public function testAddProductsToCartWithSKUCaseInsensitive(string $sku): void
72+
{
73+
$cart = $this->fixtures->get('cart');
74+
$maskedQuoteId = $this->quoteIdToMaskedQuoteId->execute((int) $cart->getId());
75+
76+
$query = $this->getAddToCartMutation($maskedQuoteId, $sku);
77+
$response = $this->graphQlMutation($query);
78+
$result = $response['addProductsToCart'];
79+
80+
self::assertEmpty($result['user_errors']);
81+
self::assertCount(1, $result['cart']['items']);
82+
83+
$cartItem = $result['cart']['items'][0];
84+
self::assertEquals('Upper_And_Lower_Test_Prod', $cartItem['product']['sku']);
85+
self::assertEquals(1, $cartItem['quantity']);
86+
}
87+
88+
/**
89+
* Data provider with sku in uppercase and lowercase
90+
*
91+
* @return array
92+
*/
93+
public static function skuDataProvider(): array
94+
{
95+
return [
96+
'upper' => ['UPPER_AND_LOWER_TEST_PROD'],
97+
'lower' => ['upper_and_lower_test_prod'],
98+
];
99+
}
100+
101+
/**
102+
* Returns GraphQl mutation for (addProductsToCart) adding item to cart
103+
*
104+
* @param string $maskedQuoteId
105+
* @param string $sku
106+
* @return string
107+
*/
108+
private function getAddToCartMutation(string $maskedQuoteId, string $sku): string
109+
{
110+
return <<<MUTATION
111+
mutation {
112+
addProductsToCart(
113+
cartId: "{$maskedQuoteId}",
114+
cartItems: [
115+
{
116+
sku: "{$sku}"
117+
quantity: 1
118+
}
119+
]
120+
) {
121+
cart {
122+
id
123+
items {
124+
uid
125+
quantity
126+
product {
127+
sku
128+
name
129+
}
130+
}
131+
}
132+
user_errors {
133+
code
134+
message
135+
}
136+
}
137+
}
138+
MUTATION;
139+
}
140+
}

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

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,22 @@
99

1010
use Exception;
1111
use Magento\Catalog\Api\ProductRepositoryInterface;
12+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
13+
use Magento\Catalog\Test\Fixture\ProductStock as ProductStockFixture;
14+
use Magento\ConfigurableProduct\Test\Fixture\AddProductToCart as AddConfigurableProductToCartFixture;
15+
use Magento\ConfigurableProduct\Test\Fixture\Attribute as AttributeFixture;
16+
use Magento\ConfigurableProduct\Test\Fixture\Product as ConfigurableProductFixture;
17+
use Magento\Framework\Exception\NoSuchEntityException;
18+
use Magento\Quote\Model\Quote\Item;
1219
use Magento\Quote\Model\QuoteFactory;
1320
use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
1421
use Magento\Quote\Model\ResourceModel\Quote as QuoteResource;
22+
use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
23+
use Magento\Quote\Test\Fixture\GuestCart as GuestCartFixture;
24+
use Magento\Quote\Test\Fixture\QuoteIdMask as QuoteMaskFixture;
25+
use Magento\TestFramework\Fixture\DataFixture;
26+
use Magento\TestFramework\Fixture\DataFixtureStorage;
27+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
1528
use Magento\TestFramework\Helper\Bootstrap;
1629
use Magento\TestFramework\TestCase\GraphQlAbstract;
1730

@@ -40,13 +53,19 @@ class UpdateCartItemsTest extends GraphQlAbstract
4053
*/
4154
private $productRepository;
4255

56+
/**
57+
* @var DataFixtureStorage
58+
*/
59+
private $fixtures;
60+
4361
protected function setUp(): void
4462
{
4563
$objectManager = Bootstrap::getObjectManager();
4664
$this->quoteResource = $objectManager->get(QuoteResource::class);
4765
$this->quoteFactory = $objectManager->get(QuoteFactory::class);
4866
$this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class);
4967
$this->productRepository = $objectManager->get(ProductRepositoryInterface::class);
68+
$this->fixtures = DataFixtureStorageManager::getStorage();
5069
}
5170

5271
/**
@@ -320,6 +339,88 @@ public function testUpdateGiftMessageCartForItem()
320339
}
321340
}
322341

342+
#[
343+
DataFixture(ProductFixture::class, as: 'configProd1'),
344+
DataFixture(ProductFixture::class, as: 'configProd2'),
345+
DataFixture(AttributeFixture::class, as: 'attr'),
346+
DataFixture(
347+
ConfigurableProductFixture::class,
348+
['_options' => ['$attr$'], '_links' => ['$configProd1$', '$configProd2$']],
349+
'configurableProduct'
350+
),
351+
DataFixture(ProductFixture::class, as: 'simpleProduct'),
352+
DataFixture(GuestCartFixture::class, ['reserved_order_id' => 'test_quote'], 'cart'),
353+
DataFixture(
354+
AddConfigurableProductToCartFixture::class,
355+
[
356+
'cart_id' => '$cart.id$',
357+
'product_id' => '$configurableProduct.id$',
358+
'child_product_id' => '$configProd1.id$',
359+
'qty' => 10
360+
],
361+
),
362+
DataFixture(
363+
AddProductToCartFixture::class,
364+
[
365+
'cart_id' => '$cart.id$',
366+
'product_id' => '$simpleProduct.id$',
367+
'qty' => 10
368+
]
369+
),
370+
//We are reducing the stock of confProd1 to 6, which is less than the quantity (10) in cart
371+
DataFixture(ProductStockFixture::class, ['prod_id' => '$configProd1.id$', 'prod_qty' => 6]),
372+
DataFixture(QuoteMaskFixture::class, ['cart_id' => '$cart.id$'], 'quoteIdMask'),
373+
]
374+
/**
375+
* Test updateCartItems GQL error when removing other products with insufficient configurable product in cart
376+
*
377+
* configProd1 & simpleProduct is added to cart with quantity 10.
378+
* configProd1 stock is reduced to 6. So requested qty of configProd1 is not available now.
379+
* updateCartItems mutation is used to remove simpleProduct from cart
380+
*/
381+
public function testRemoveCartItemIfOtherProductStockIsReduced(): void
382+
{
383+
$maskedQuoteId = $this->fixtures->get('quoteIdMask')->getMaskedId();
384+
$simpleProdSku = $this->fixtures->get('simpleProduct')->getSku();
385+
$simpleProdId = $this->getQuoteItemIdBySku($simpleProdSku);
386+
$quantity = 0.0;
387+
388+
/*
389+
* Set simple product quantity to 0.
390+
* This will remove simple product from cart
391+
*/
392+
$query = $this->getQuery($maskedQuoteId, $simpleProdId, $quantity);
393+
$mutationResponse = $this->graphQlMutation($query);
394+
$this->assertArrayHasKey('updateCartItems', $mutationResponse);
395+
$this->assertArrayHasKey('cart', $mutationResponse['updateCartItems']);
396+
$this->assertArrayHasKey('items', $mutationResponse['updateCartItems']['cart']);
397+
$mutationResponseCartItems = $mutationResponse['updateCartItems']['cart']['items'];
398+
$this->assertCount(1, $mutationResponseCartItems);
399+
//Check that update is correctly reflected in cart
400+
$cartQuery = $this->getCartQuery($maskedQuoteId);
401+
$cartResponse = $this->graphQlQuery($cartQuery);
402+
$cartResponseItems = $cartResponse['cart']['items'];
403+
$this->assertCount(1, $cartResponseItems);
404+
}
405+
406+
/**
407+
* Returns quote item id by product's SKU
408+
*
409+
* @param string $sku
410+
* @return int
411+
* @throws NoSuchEntityException
412+
*/
413+
private function getQuoteItemIdBySku(string $sku): int
414+
{
415+
$quote = $this->quoteFactory->create();
416+
$product = $this->productRepository->get($sku);
417+
$this->quoteResource->load($quote, 'test_quote', 'reserved_order_id');
418+
/** @var Item $quoteItem */
419+
$quoteItem = $quote->getItemByProduct($product);
420+
421+
return (int)$quoteItem->getId();
422+
}
423+
323424
private function getUpdateGiftMessageQuery(string $messageTo, string $messageFrom, string $message)
324425
{
325426
$quote = $this->quoteFactory->create();

0 commit comments

Comments
 (0)