-
Notifications
You must be signed in to change notification settings - Fork 154
Mutations coupons #163
Mutations coupons #163
Changes from 5 commits
ced2301
6abc7e5
b6eaa1f
1a077ac
9cb459e
ba6dd12
02c2bc0
7f1148f
b6365e1
3007b3a
2a0a450
462601c
2f4767d
343e463
46b40b4
fc12cb7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
|
||
use Magento\Authorization\Model\UserContextInterface; | ||
use Magento\Framework\Exception\NoSuchEntityException; | ||
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; | ||
use Magento\Quote\Api\CartRepositoryInterface; | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
class CartMutationsAllowed implements CartMutationsAllowedInterface | ||
{ | ||
/** | ||
* @var CartRepositoryInterface | ||
*/ | ||
private $cartRepository; | ||
|
||
/** | ||
* @var UserContextInterface | ||
*/ | ||
private $userContext; | ||
|
||
/** | ||
* @param UserContextInterface $userContext | ||
* @param CartRepositoryInterface $cartRepository | ||
*/ | ||
public function __construct( | ||
UserContextInterface $userContext, | ||
CartRepositoryInterface $cartRepository | ||
) { | ||
$this->userContext = $userContext; | ||
$this->cartRepository = $cartRepository; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function execute(int $quoteId): bool | ||
{ | ||
try { | ||
$quote = $this->cartRepository->get($quoteId); | ||
} catch (NoSuchEntityException $exception) { | ||
throw new GraphQlNoSuchEntityException(__($exception->getMessage())); | ||
} | ||
|
||
$customerId = $quote->getCustomerId(); | ||
|
||
if (!$customerId) { | ||
return true; | ||
} | ||
|
||
if ($customerId == $this->userContext->getUserId()) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\QuoteGraphQl\Model; | ||
|
||
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; | ||
|
||
/** | ||
* Service for checking that the shopping cart operations | ||
* are allowed for current user | ||
*/ | ||
interface CartMutationsAllowedInterface | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All classes/interfaces should be named using nouns. Please consider making changes across the review. In this specific case something like |
||
{ | ||
/** | ||
* @param int $quoteId | ||
* @return bool | ||
* @throws GraphQlNoSuchEntityException | ||
*/ | ||
public function execute(int $quoteId): bool; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\QuoteGraphQl\Model\Resolver\Coupon; | ||
|
||
use Magento\Framework\Exception\NoSuchEntityException; | ||
use Magento\Framework\GraphQl\Config\Element\Field; | ||
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; | ||
use Magento\Framework\GraphQl\Exception\GraphQlInputException; | ||
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; | ||
use Magento\Framework\GraphQl\Query\Resolver\Value; | ||
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; | ||
use Magento\Framework\GraphQl\Query\ResolverInterface; | ||
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; | ||
use Magento\Quote\Api\CouponManagementInterface; | ||
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; | ||
use Magento\QuoteGraphQl\Model\CartMutationsAllowedInterface; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
class ApplyCouponToCart implements ResolverInterface | ||
{ | ||
/** | ||
* @var CouponManagementInterface | ||
*/ | ||
private $couponManagement; | ||
|
||
/** | ||
* @var ValueFactory | ||
*/ | ||
private $valueFactory; | ||
|
||
/** | ||
* @var MaskedQuoteIdToQuoteIdInterface | ||
*/ | ||
private $maskedQuoteIdToQuoteId; | ||
|
||
/** | ||
* @var CartMutationsAllowedInterface | ||
*/ | ||
private $cartMutationsAllowed; | ||
|
||
/** | ||
* @param ValueFactory $valueFactory | ||
* @param CouponManagementInterface $couponManagement | ||
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToId | ||
* @param CartMutationsAllowedInterface $cartMutationsAllowed | ||
*/ | ||
public function __construct( | ||
ValueFactory $valueFactory, | ||
CouponManagementInterface $couponManagement, | ||
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToId, | ||
CartMutationsAllowedInterface $cartMutationsAllowed | ||
) { | ||
$this->valueFactory = $valueFactory; | ||
$this->couponManagement = $couponManagement; | ||
$this->maskedQuoteIdToQuoteId = $maskedQuoteIdToId; | ||
$this->cartMutationsAllowed = $cartMutationsAllowed; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value | ||
{ | ||
$maskedQuoteId = $args['input']['cart_id']; | ||
$couponCode = $args['input']['coupon_code']; | ||
|
||
if (!$maskedQuoteId || !$couponCode) { | ||
throw new GraphQlInputException(__('Required parameter is missing')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is better to specify which parameter is missing (have two separate exceptions) |
||
} | ||
|
||
try { | ||
$cartId = $this->maskedQuoteIdToQuoteId->execute($maskedQuoteId); | ||
} catch (NoSuchEntityException $exception) { | ||
throw new GraphQlNoSuchEntityException(__('No cart with provided ID found')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you can include the ID, then change the exception text to 'Could not find a cart with ID <ID_number>' Otherwise, change exception text to 'Could not find a cart with the provided ID' |
||
} | ||
|
||
if (!$this->cartMutationsAllowed->execute($cartId)) { | ||
throw new GraphQlAuthorizationException( | ||
__('Operations with selected cart is not permitted for current user') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 'cart is not permitted' => 'cart are not permitted' There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you can include the cart ID, change exception text to Otherwise, change the text to |
||
); | ||
} | ||
|
||
/* Check current cart does not have coupon code applied */ | ||
$appliedCouponCode = $this->couponManagement->get($cartId); | ||
if (!empty($appliedCouponCode)) { | ||
throw new GraphQlInputException( | ||
__('A coupon is already applied to the cart. Please remove it to apply another') | ||
); | ||
} | ||
|
||
try { | ||
$this->couponManagement->set($cartId, $couponCode); | ||
} catch (\Exception $exception) { | ||
throw new GraphQlInputException(__($exception->getMessage())); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We must not display exception messages from Please make sure to fix similar issues across the PR if any. |
||
} | ||
|
||
$data['cart']['applied_coupon'] = [ | ||
'code' => $couponCode | ||
]; | ||
|
||
$result = function () use ($data) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How is it possible to get the full cart object if needed? |
||
return $data; | ||
}; | ||
|
||
return $this->valueFactory->create($result); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\QuoteGraphQl\Model\Resolver\Coupon; | ||
|
||
use Magento\Framework\Exception\NoSuchEntityException; | ||
use Magento\Framework\GraphQl\Config\Element\Field; | ||
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; | ||
use Magento\Framework\GraphQl\Exception\GraphQlInputException; | ||
use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; | ||
use Magento\Framework\GraphQl\Query\Resolver\Value; | ||
use Magento\Framework\GraphQl\Query\Resolver\ValueFactory; | ||
use Magento\Framework\GraphQl\Query\ResolverInterface; | ||
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; | ||
use Magento\Quote\Api\CouponManagementInterface; | ||
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; | ||
use Magento\QuoteGraphQl\Model\CartMutationsAllowedInterface; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
class RemoveCouponFromCart implements ResolverInterface | ||
{ | ||
/** | ||
* @var MaskedQuoteIdToQuoteIdInterface | ||
*/ | ||
private $maskedQuoteIdToId; | ||
|
||
/** | ||
* @var CouponManagementInterface | ||
*/ | ||
private $couponManagement; | ||
/** | ||
* @var ValueFactory | ||
*/ | ||
private $valueFactory; | ||
|
||
/** | ||
* @var CartMutationsAllowedInterface | ||
*/ | ||
private $cartMutationsAllowed; | ||
|
||
/** | ||
* @param ValueFactory $valueFactory | ||
* @param CouponManagementInterface $couponManagement | ||
* @param CartMutationsAllowedInterface $cartMutationsAllowed | ||
* @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToId | ||
*/ | ||
public function __construct( | ||
ValueFactory $valueFactory, | ||
CouponManagementInterface $couponManagement, | ||
CartMutationsAllowedInterface $cartMutationsAllowed, | ||
MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToId | ||
) { | ||
$this->valueFactory = $valueFactory; | ||
$this->couponManagement = $couponManagement; | ||
$this->cartMutationsAllowed = $cartMutationsAllowed; | ||
$this->maskedQuoteIdToId = $maskedQuoteIdToId; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function resolve(Field $field, $context, ResolveInfo $info, array $value = null, array $args = null) : Value | ||
{ | ||
$maskedCartId = $args['input']['cart_id']; | ||
|
||
if (!$maskedCartId) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apply the same edits to the exception text as with |
||
throw new GraphQlInputException(__('Required parameter is missing')); | ||
} | ||
|
||
try { | ||
$cartId = $this->maskedQuoteIdToId->execute($maskedCartId); | ||
} catch (NoSuchEntityException $exception) { | ||
throw new GraphQlNoSuchEntityException(__('No cart with provided ID found')); | ||
} | ||
|
||
if (!$this->cartMutationsAllowed->execute((int) $cartId)) { | ||
throw new GraphQlAuthorizationException( | ||
__('Operations with selected cart is not permitted for current user') | ||
); | ||
} | ||
|
||
try { | ||
$this->couponManagement->remove($cartId); | ||
} catch (\Exception $exception) { | ||
throw new GraphQlInputException(__($exception->getMessage())); | ||
} | ||
|
||
$data['cart']['applied_coupon'] = [ | ||
'code' => '' | ||
]; | ||
|
||
$result = function () use ($data) { | ||
return $data; | ||
}; | ||
|
||
return $this->valueFactory->create($result); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0"?> | ||
<!-- | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
--> | ||
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> | ||
<preference for="Magento\QuoteGraphQl\Model\CartMutationsAllowedInterface" type="Magento\QuoteGraphQl\Model\CartMutationsAllowed" /> | ||
</config> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,36 @@ | |
|
||
type Mutation { | ||
createEmptyCart: String @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Cart\\CreateEmptyCart") @doc(description:"Creates empty shopping cart for guest or logged in user") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change description to Creates an empty shopping cart for a guest or a logged in user |
||
applyCouponToCart(input: ApplyCouponToCartInput): ApplyCouponToCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\ApplyCouponToCart") | ||
removeCouponFromCart(input: RemoveCouponFromCartInput): RemoveCouponFromCartOutput @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\Coupon\\RemoveCouponFromCart") | ||
} | ||
|
||
input ApplyCouponToCartInput { | ||
cart_id: String! | ||
coupon_code: String! | ||
} | ||
|
||
type ApplyCouponToCartOutput { | ||
cart: Cart! | ||
} | ||
|
||
type Cart { | ||
applied_coupon: AppliedCoupon | ||
} | ||
|
||
type CartAddress { | ||
applied_coupon: AppliedCoupon | ||
} | ||
|
||
type AppliedCoupon { | ||
# Wrapper allows for future extension of coupon info | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably don't need to leave such comments in the schema. |
||
code: String! | ||
} | ||
|
||
input RemoveCouponFromCartInput { | ||
cart_id: String! | ||
} | ||
|
||
type RemoveCouponFromCartOutput { | ||
cart: Cart | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add comments to explain allowed use cases. It might be not obvious why we have these checks.