Skip to content

Commit d04bf94

Browse files
committed
Merge remote-tracking branch 'andrewbess/CE-30469' into HB-PR-delivery-Oct
2 parents 1db3fc3 + 647628a commit d04bf94

File tree

3 files changed

+149
-18
lines changed

3 files changed

+149
-18
lines changed

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

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,24 @@
77

88
namespace Magento\QuoteGraphQl\Model\Resolver;
99

10+
use Magento\Framework\App\ObjectManager;
11+
use Magento\Framework\Exception\CouldNotSaveException;
1012
use Magento\Framework\GraphQl\Config\Element\Field;
13+
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
1114
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
15+
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
1216
use Magento\Framework\GraphQl\Query\ResolverInterface;
1317
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
14-
use Magento\QuoteGraphQl\Model\Cart\GetCartForUser;
15-
use Magento\Quote\Api\CartRepositoryInterface;
1618
use Magento\GraphQl\Model\Query\ContextInterface;
17-
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
19+
use Magento\Quote\Api\CartRepositoryInterface;
20+
use Magento\Quote\Model\Cart\CustomerCartResolver;
21+
use Magento\Quote\Model\QuoteIdToMaskedQuoteIdInterface;
22+
use Magento\QuoteGraphQl\Model\Cart\GetCartForUser;
1823

1924
/**
2025
* Merge Carts Resolver
26+
*
27+
* @SuppressWarnings(PHPMD.LongVariable)
2128
*/
2229
class MergeCarts implements ResolverInterface
2330
{
@@ -31,44 +38,95 @@ class MergeCarts implements ResolverInterface
3138
*/
3239
private $cartRepository;
3340

41+
/**
42+
* @var CustomerCartResolver
43+
*/
44+
private $customerCartResolver;
45+
46+
/**
47+
* @var QuoteIdToMaskedQuoteIdInterface
48+
*/
49+
private $quoteIdToMaskedQuoteId;
50+
3451
/**
3552
* @param GetCartForUser $getCartForUser
3653
* @param CartRepositoryInterface $cartRepository
54+
* @param CustomerCartResolver|null $customerCartResolver
55+
* @param QuoteIdToMaskedQuoteIdInterface|null $quoteIdToMaskedQuoteId
3756
*/
3857
public function __construct(
3958
GetCartForUser $getCartForUser,
40-
CartRepositoryInterface $cartRepository
59+
CartRepositoryInterface $cartRepository,
60+
CustomerCartResolver $customerCartResolver = null,
61+
QuoteIdToMaskedQuoteIdInterface $quoteIdToMaskedQuoteId = null
4162
) {
4263
$this->getCartForUser = $getCartForUser;
4364
$this->cartRepository = $cartRepository;
65+
$this->customerCartResolver = $customerCartResolver
66+
?: ObjectManager::getInstance()->get(CustomerCartResolver::class);
67+
$this->quoteIdToMaskedQuoteId = $quoteIdToMaskedQuoteId
68+
?: ObjectManager::getInstance()->get(QuoteIdToMaskedQuoteIdInterface::class);
4469
}
4570

4671
/**
4772
* @inheritdoc
4873
*/
49-
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
50-
{
74+
public function resolve(
75+
Field $field,
76+
$context,
77+
ResolveInfo $info,
78+
array $value = null,
79+
array $args = null
80+
) {
5181
if (empty($args['source_cart_id'])) {
52-
throw new GraphQlInputException(__('Required parameter "source_cart_id" is missing'));
53-
}
54-
55-
if (empty($args['destination_cart_id'])) {
56-
throw new GraphQlInputException(__('Required parameter "destination_cart_id" is missing'));
82+
throw new GraphQlInputException(__(
83+
'Required parameter "source_cart_id" is missing'
84+
));
5785
}
5886

5987
/** @var ContextInterface $context */
6088
if (false === $context->getExtensionAttributes()->getIsCustomer()) {
61-
throw new GraphQlAuthorizationException(__('The current customer isn\'t authorized.'));
89+
throw new GraphQlAuthorizationException(__(
90+
'The current customer isn\'t authorized.'
91+
));
92+
}
93+
$currentUserId = $context->getUserId();
94+
95+
if (!isset($args['destination_cart_id'])) {
96+
try {
97+
$cart = $this->customerCartResolver->resolve($currentUserId);
98+
} catch (CouldNotSaveException $exception) {
99+
throw new GraphQlNoSuchEntityException(
100+
__('Could not create empty cart for customer'),
101+
$exception
102+
);
103+
}
104+
$customerMaskedCartId = $this->quoteIdToMaskedQuoteId->execute(
105+
(int) $cart->getId()
106+
);
107+
} else {
108+
if (empty($args['destination_cart_id'])) {
109+
throw new GraphQlInputException(__(
110+
'The parameter "destination_cart_id" cannot be empty'
111+
));
112+
}
62113
}
63114

64115
$guestMaskedCartId = $args['source_cart_id'];
65-
$customerMaskedCartId = $args['destination_cart_id'];
116+
$customerMaskedCartId = $customerMaskedCartId ?? $args['destination_cart_id'];
66117

67-
$currentUserId = $context->getUserId();
68118
$storeId = (int)$context->getExtensionAttributes()->getStore()->getId();
69119
// passing customerId as null enforces source cart should always be a guestcart
70-
$guestCart = $this->getCartForUser->execute($guestMaskedCartId, null, $storeId);
71-
$customerCart = $this->getCartForUser->execute($customerMaskedCartId, $currentUserId, $storeId);
120+
$guestCart = $this->getCartForUser->execute(
121+
$guestMaskedCartId,
122+
null,
123+
$storeId
124+
);
125+
$customerCart = $this->getCartForUser->execute(
126+
$customerMaskedCartId,
127+
$currentUserId,
128+
$storeId
129+
);
72130
$customerCart->merge($guestCart);
73131
$guestCart->setIsActive(false);
74132
$this->cartRepository->save($customerCart);

app/code/Magento/QuoteGraphQl/etc/schema.graphqls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type Mutation {
2020
setPaymentMethodOnCart(input: SetPaymentMethodOnCartInput): SetPaymentMethodOnCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\SetPaymentMethodOnCart")
2121
setGuestEmailOnCart(input: SetGuestEmailOnCartInput): SetGuestEmailOnCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\SetGuestEmailOnCart")
2222
setPaymentMethodAndPlaceOrder(input: SetPaymentMethodAndPlaceOrderInput): PlaceOrderOutput @deprecated(reason: "Should use setPaymentMethodOnCart and placeOrder mutations in single request.") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetPaymentAndPlaceOrder")
23-
mergeCarts(source_cart_id: String!, destination_cart_id: String!): Cart! @doc(description:"Merges the source cart into the destination cart") @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\MergeCarts")
23+
mergeCarts(source_cart_id: String!, destination_cart_id: String): Cart! @doc(description:"Merges the source cart into the destination cart") @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\MergeCarts")
2424
placeOrder(input: PlaceOrderInput): PlaceOrderOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\PlaceOrder")
2525
addProductsToCart(cartId: String!, cartItems: [CartItemInput!]!): AddProductsToCartOutput @doc(description:"Add any type of product to the cart") @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\AddProductsToCart")
2626
}

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

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public function testMergeCartsWithEmptySourceCartId()
193193
public function testMergeCartsWithEmptyDestinationCartId()
194194
{
195195
$this->expectException(\Exception::class);
196-
$this->expectExceptionMessage('Required parameter "destination_cart_id" is missing');
196+
$this->expectExceptionMessage('The parameter "destination_cart_id" cannot be empty');
197197

198198
$guestQuote = $this->quoteFactory->create();
199199
$this->quoteResource->load(
@@ -209,6 +209,54 @@ public function testMergeCartsWithEmptyDestinationCartId()
209209
$this->graphQlMutation($query, [], '', $this->getHeaderMap());
210210
}
211211

212+
/**
213+
* @magentoApiDataFixture Magento/Checkout/_files/quote_with_virtual_product_saved.php
214+
* @magentoApiDataFixture Magento/Customer/_files/customer.php
215+
* @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php
216+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php
217+
* @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php
218+
*/
219+
public function testMergeCartsWithoutDestinationCartId()
220+
{
221+
$guestQuote = $this->quoteFactory->create();
222+
$this->quoteResource->load(
223+
$guestQuote,
224+
'test_order_with_virtual_product_without_address',
225+
'reserved_order_id'
226+
);
227+
$guestQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$guestQuote->getId());
228+
$query = $this->getCartMergeMutationWithoutDestinationCartId(
229+
$guestQuoteMaskedId
230+
);
231+
$mergeResponse = $this->graphQlMutation($query, [], '', $this->getHeaderMap());
232+
233+
self::assertArrayHasKey('mergeCarts', $mergeResponse);
234+
$cartResponse = $mergeResponse['mergeCarts'];
235+
self::assertArrayHasKey('items', $cartResponse);
236+
self::assertCount(2, $cartResponse['items']);
237+
238+
$customerQuote = $this->quoteFactory->create();
239+
$this->quoteResource->load($customerQuote, 'test_quote', 'reserved_order_id');
240+
$customerQuoteMaskedId = $this->quoteIdToMaskedId->execute((int)$customerQuote->getId());
241+
242+
$cartResponse = $this->graphQlMutation(
243+
$this->getCartQuery($customerQuoteMaskedId),
244+
[],
245+
'',
246+
$this->getHeaderMap()
247+
);
248+
249+
self::assertArrayHasKey('cart', $cartResponse);
250+
self::assertArrayHasKey('items', $cartResponse['cart']);
251+
self::assertCount(2, $cartResponse['cart']['items']);
252+
$item1 = $cartResponse['cart']['items'][0];
253+
self::assertArrayHasKey('quantity', $item1);
254+
self::assertEquals(2, $item1['quantity']);
255+
$item2 = $cartResponse['cart']['items'][1];
256+
self::assertArrayHasKey('quantity', $item2);
257+
self::assertEquals(1, $item2['quantity']);
258+
}
259+
212260
/**
213261
* Add simple product to cart
214262
*
@@ -256,6 +304,31 @@ private function getCartMergeMutation(string $guestQuoteMaskedId, string $custom
256304
QUERY;
257305
}
258306

307+
/**
308+
* Create the mergeCart mutation
309+
*
310+
* @param string $guestQuoteMaskedId
311+
* @return string
312+
*/
313+
private function getCartMergeMutationWithoutDestinationCartId(
314+
string $guestQuoteMaskedId
315+
): string {
316+
return <<<QUERY
317+
mutation {
318+
mergeCarts(
319+
source_cart_id: "{$guestQuoteMaskedId}"
320+
){
321+
items {
322+
quantity
323+
product {
324+
sku
325+
}
326+
}
327+
}
328+
}
329+
QUERY;
330+
}
331+
259332
/**
260333
* Get cart query
261334
*

0 commit comments

Comments
 (0)