Skip to content
This repository was archived by the owner on Dec 19, 2019. It is now read-only.

Add Merge Cart Mutation #950

Merged
merged 2 commits into from
Nov 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions app/code/Magento/QuoteGraphQl/Model/Cart/GetCart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\QuoteGraphQl\Model\Cart;

use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
use Magento\Quote\Model\Quote;

/**
* Get cart merge
*/
class GetCart
{
/**
* @var MaskedQuoteIdToQuoteIdInterface
*/
private $maskedQuoteIdToQuoteId;

/**
* @var CartRepositoryInterface
*/
private $cartRepository;

/**
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
* @param CartRepositoryInterface $cartRepository
*/
public function __construct(
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
CartRepositoryInterface $cartRepository
) {
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
$this->cartRepository = $cartRepository;
}

/**
* Get cart for merge
*
* @param string $cartHash
* @param int|null $customerId
* @param int $storeId
* @return Quote
* @throws GraphQlNoSuchEntityException
* @throws NoSuchEntityException
*/
public function execute(string $cartHash, ?int $customerId, int $storeId): Quote
{
try {
$cartId = $this->maskedQuoteIdToQuoteId->execute($cartHash);
} catch (NoSuchEntityException $exception) {
throw new GraphQlNoSuchEntityException(
__('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash])
);
}

try {
/** @var Quote $cart */
$cart = $this->cartRepository->get($cartId);
} catch (NoSuchEntityException $e) {
throw new GraphQlNoSuchEntityException(
__('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash])
);
}

if ((int)$cart->getStoreId() !== $storeId) {
throw new GraphQlNoSuchEntityException(
__(
'Wrong store code specified for cart "%masked_cart_id"',
['masked_cart_id' => $cartHash]
)
);
}

$cartCustomerId = (int)$cart->getCustomerId();

/* Guest cart, allow operations */
if (0 === $cartCustomerId) {
return $cart;
}

if ($cartCustomerId !== $customerId) {
throw new GraphQlNoSuchEntityException(
__('The current user cannot perform operations on cart "%masked_cart_id"', ['masked_cart_id' => $cartHash])
);
}
return $cart;
}
}
46 changes: 6 additions & 40 deletions app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
use Magento\Quote\Model\Quote;

/**
Expand All @@ -20,25 +18,17 @@
class GetCartForUser
{
/**
* @var MaskedQuoteIdToQuoteIdInterface
* @var GetCart
*/
private $maskedQuoteIdToQuoteId;
private $getCart;

/**
* @var CartRepositoryInterface
*/
private $cartRepository;

/**
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId
* @param CartRepositoryInterface $cartRepository
* @param GetCart $getCart
*/
public function __construct(
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId,
CartRepositoryInterface $cartRepository
GetCart $getCart
) {
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId;
$this->cartRepository = $cartRepository;
$this->getCart = $getCart;
}

/**
Expand All @@ -54,38 +44,14 @@ public function __construct(
*/
public function execute(string $cartHash, ?int $customerId, int $storeId): Quote
{
try {
$cartId = $this->maskedQuoteIdToQuoteId->execute($cartHash);
} catch (NoSuchEntityException $exception) {
throw new GraphQlNoSuchEntityException(
__('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash])
);
}

try {
/** @var Quote $cart */
$cart = $this->cartRepository->get($cartId);
} catch (NoSuchEntityException $e) {
throw new GraphQlNoSuchEntityException(
__('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash])
);
}
$cart = $this->getCart->execute($cartHash, $customerId, $storeId);

if (false === (bool)$cart->getIsActive()) {
throw new GraphQlNoSuchEntityException(
__('Current user does not have an active cart.')
);
}

if ((int)$cart->getStoreId() !== $storeId) {
throw new GraphQlNoSuchEntityException(
__(
'Wrong store code specified for cart "%masked_cart_id"',
['masked_cart_id' => $cartHash]
)
);
}

$cartCustomerId = (int)$cart->getCustomerId();

/* Guest cart, allow operations */
Expand Down
91 changes: 91 additions & 0 deletions app/code/Magento/QuoteGraphQl/Model/Cart/MergeCarts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\QuoteGraphQl\Model\Cart;

use Magento\Quote\Model\Quote;
use Magento\Quote\Model\QuoteIdMask;
use Magento\Quote\Model\QuoteIdMaskFactory;
use Magento\Quote\Model\ResourceModel\Quote\QuoteIdMask as QuoteIdMaskResourceModel;
use Magento\Quote\Api\CartRepositoryInterface;

/**
* Merge two carts
*/
class MergeCarts
{
/**
* @var QuoteIdMaskFactory
*/
private $quoteMaskFactory;

/**
* @var QuoteIdMaskResourceModel
*/
private $quoteMaskResource;

/**
* @var CartRepositoryInterface
*/
private $cartRepository;

/**
* @param QuoteIdMaskFactory $quoteMaskFactory
* @param QuoteIdMaskResourceModel $quoteMaskResource
* @param CartRepositoryInterface $cartRepository
*/
public function __construct(
QuoteIdMaskFactory $quoteMaskFactory,
QuoteIdMaskResourceModel $quoteMaskResource,
CartRepositoryInterface $cartRepository
) {
$this->quoteMaskFactory = $quoteMaskFactory;
$this->quoteMaskResource = $quoteMaskResource;
$this->cartRepository = $cartRepository;
}

/**
* Merge two quotes
*
* @param Quote $firstCart
* @param Quote $secondQuote
* @return string
*/
public function execute(Quote $firstCart, Quote $secondQuote): string
{
$firstCart->merge($secondQuote);
$firstCart->setIsActive(true);

$this->updateMaskedId($secondQuote);
$maskedQuoteId = $this->updateMaskedId($firstCart);

$this->cartRepository->save($firstCart);

$secondQuote->setIsActive(false);
$this->cartRepository->save($secondQuote);

return $maskedQuoteId;
}

/**
* Update quote masked id
*
* @param Quote $quote
* @return string
*/
private function updateMaskedId(Quote $quote): string
{
/** @var QuoteIdMask $quoteIdMask */
$quoteIdMask = $this->quoteMaskFactory->create();
$this->quoteMaskResource->load($quoteIdMask, $quote->getId(), 'quote_id');
$quoteIdMask->unsetData('masked_id');
$this->quoteMaskResource->save($quoteIdMask);
$maskedId = $quoteIdMask->getMaskedId();

return $maskedId;
}
}
65 changes: 65 additions & 0 deletions app/code/Magento/QuoteGraphQl/Model/Resolver/MergeCarts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\QuoteGraphQl\Model\Resolver;

use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\QuoteGraphQl\Model\Cart\GetCart;
use Magento\QuoteGraphQl\Model\Cart\MergeCarts as MergeCartsModel;

/**
* @inheritdoc
*/
class MergeCarts implements ResolverInterface
{
/**
* @var GetCart
*/
private $getCart;

/**
* @var MergeCartsModel
*/
private $mergeCarts;

/**
* @param GetCart $getCart
* @param MergeCartsModel $mergeCarts
*/
public function __construct(
GetCart $getCart,
MergeCartsModel $mergeCarts
) {
$this->getCart = $getCart;
$this->mergeCarts = $mergeCarts;
}

/**
* @inheritdoc
*/
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null)
{
if (empty($args['input']['first_cart_id'])) {
throw new GraphQlInputException(__('Required parameter "first_cart_id" is missing'));
}
if (empty($args['input']['second_cart_id'])) {
throw new GraphQlInputException(__('Required parameter "second_cart_id" is missing'));
}

$currentUserId = $context->getUserId();
$storeId = $storeId = (int) $context->getExtensionAttributes()->getStore()->getId();
$firstCart = $this->getCart->execute($args['input']['first_cart_id'], $currentUserId, $storeId);
$secondCart = $this->getCart->execute($args['input']['second_cart_id'], $currentUserId, $storeId);

$maskedQuoteId = $this->mergeCarts->execute($firstCart, $secondCart);

return $maskedQuoteId;
}
}
6 changes: 6 additions & 0 deletions app/code/Magento/QuoteGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type Mutation {
setGuestEmailOnCart(input: SetGuestEmailOnCartInput): SetGuestEmailOnCartOutput @resolver(class: "Magento\\QuoteGraphQl\\Model\\Resolver\\SetGuestEmailOnCart")
setPaymentMethodAndPlaceOrder(input: SetPaymentMethodAndPlaceOrderInput): PlaceOrderOutput @deprecated(reason: "Should use setPaymentMethodOnCart and placeOrder mutations in single request.") @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\SetPaymentAndPlaceOrder")
placeOrder(input: PlaceOrderInput): PlaceOrderOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\PlaceOrder")
mergeCarts(input: MergeCartsInput): String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\MergeCarts")
}

input createEmptyCartInput {
Expand Down Expand Up @@ -146,6 +147,11 @@ input SetGuestEmailOnCartInput {
email: String!
}

input MergeCartsInput {
first_cart_id: String!
second_cart_id: String!
}

type CartPrices {
grand_total: Money
subtotal_including_tax: Money
Expand Down
Loading