diff --git a/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php b/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php index 2086646d855f..9be1e9d32e37 100644 --- a/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php +++ b/app/code/Magento/Quote/Model/Cart/AddProductsToCart.php @@ -7,8 +7,6 @@ namespace Magento\Quote\Model\Cart; -use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Model\Cart\BuyRequest\BuyRequestBuilder; @@ -23,29 +21,6 @@ */ class AddProductsToCart { - /**#@+ - * Error message codes - */ - private const ERROR_PRODUCT_NOT_FOUND = 'PRODUCT_NOT_FOUND'; - private const ERROR_INSUFFICIENT_STOCK = 'INSUFFICIENT_STOCK'; - private const ERROR_NOT_SALABLE = 'NOT_SALABLE'; - private const ERROR_UNDEFINED = 'UNDEFINED'; - /**#@-*/ - - /** - * List of error messages and codes. - */ - private const MESSAGE_CODES = [ - 'Could not find a product with SKU' => self::ERROR_PRODUCT_NOT_FOUND, - 'The required options you selected are not available' => self::ERROR_NOT_SALABLE, - 'Product that you are trying to add is not available.' => self::ERROR_NOT_SALABLE, - 'This product is out of stock' => self::ERROR_INSUFFICIENT_STOCK, - 'There are no source items' => self::ERROR_NOT_SALABLE, - 'The fewest you may purchase is' => self::ERROR_INSUFFICIENT_STOCK, - 'The most you may purchase is' => self::ERROR_INSUFFICIENT_STOCK, - 'The requested qty is not available' => self::ERROR_INSUFFICIENT_STOCK, - ]; - /** * @var CartRepositoryInterface */ @@ -67,25 +42,29 @@ class AddProductsToCart private $productReader; /** - * @param ProductRepositoryInterface $productRepository + * @var AddProductsToCartError + */ + private $error; + + /** * @param CartRepositoryInterface $cartRepository * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId * @param BuyRequestBuilder $requestBuilder - * @param ProductReaderInterface|null $productReader - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @param ProductReaderInterface $productReader + * @param AddProductsToCartError $addProductsToCartError */ public function __construct( - ProductRepositoryInterface $productRepository, CartRepositoryInterface $cartRepository, MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, BuyRequestBuilder $requestBuilder, - ProductReaderInterface $productReader = null + ProductReaderInterface $productReader, + AddProductsToCartError $addProductsToCartError ) { $this->cartRepository = $cartRepository; $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->requestBuilder = $requestBuilder; - $this->productReader = $productReader ?: ObjectManager::getInstance()->get(ProductReaderInterface::class); + $this->productReader = $productReader; + $this->error = $addProductsToCartError; } /** @@ -106,7 +85,7 @@ public function execute(string $maskedCartId, array $cartItems): AddProductsToCa /** @var MessageInterface $error */ foreach ($errors as $error) { - $allErrors[] = $this->createError($error->getText()); + $allErrors[] = $this->error->create($error->getText()); } } @@ -181,14 +160,14 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt $result = null; if ($cartItem->getQuantity() <= 0) { - $errors[] = $this->createError( + $errors[] = $this->error->create( __('The product quantity should be greater than 0')->render(), $cartItemPosition ); } else { $product = $this->productReader->getProductBySku($sku); if (!$product || !$product->isSaleable() || !$product->isAvailable()) { - $errors[] = $this->createError( + $errors[] = $this->error->create( __('Could not find a product with SKU "%sku"', ['sku' => $sku])->render(), $cartItemPosition ); @@ -196,7 +175,7 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt try { $result = $cart->addProduct($product, $this->requestBuilder->build($cartItem)); } catch (\Throwable $e) { - $errors[] = $this->createError( + $errors[] = $this->error->create( __($e->getMessage())->render(), $cartItemPosition ); @@ -205,7 +184,7 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt if (is_string($result)) { foreach (array_unique(explode("\n", $result)) as $error) { - $errors[] = $this->createError(__($error)->render(), $cartItemPosition); + $errors[] = $this->error->create(__($error)->render(), $cartItemPosition); } } } @@ -213,42 +192,6 @@ private function addItemToCart(Quote $cart, Data\CartItem $cartItem, int $cartIt return $errors; } - /** - * Returns an error object - * - * @param string $message - * @param int $cartItemPosition - * @return Data\Error - */ - private function createError(string $message, int $cartItemPosition = 0): Data\Error - { - return new Data\Error( - $message, - $this->getErrorCode($message), - $cartItemPosition - ); - } - - /** - * Get message error code. - * - * TODO: introduce a separate class for getting error code from a message - * - * @param string $message - * @return string - */ - private function getErrorCode(string $message): string - { - foreach (self::MESSAGE_CODES as $codeMessage => $code) { - if (false !== stripos($message, $codeMessage)) { - return $code; - } - } - - /* If no code was matched, return the default one */ - return self::ERROR_UNDEFINED; - } - /** * Creates a new output from existing errors * diff --git a/app/code/Magento/Quote/Model/Cart/AddProductsToCartError.php b/app/code/Magento/Quote/Model/Cart/AddProductsToCartError.php new file mode 100644 index 000000000000..fe8c0d72d465 --- /dev/null +++ b/app/code/Magento/Quote/Model/Cart/AddProductsToCartError.php @@ -0,0 +1,71 @@ + self::ERROR_PRODUCT_NOT_FOUND, + 'The required options you selected are not available' => self::ERROR_NOT_SALABLE, + 'Product that you are trying to add is not available.' => self::ERROR_NOT_SALABLE, + 'This product is out of stock' => self::ERROR_INSUFFICIENT_STOCK, + 'There are no source items' => self::ERROR_NOT_SALABLE, + 'The fewest you may purchase is' => self::ERROR_INSUFFICIENT_STOCK, + 'The most you may purchase is' => self::ERROR_INSUFFICIENT_STOCK, + 'The requested qty is not available' => self::ERROR_INSUFFICIENT_STOCK, + ]; + + /** + * Returns an error object + * + * @param string $message + * @param int $cartItemPosition + * @return Data\Error + */ + public function create(string $message, int $cartItemPosition = 0): Data\Error + { + return new Data\Error( + $message, + $this->getErrorCode($message), + $cartItemPosition + ); + } + + /** + * Get message error code. + * + * @param string $message + * @return string + */ + private function getErrorCode(string $message): string + { + foreach (self::MESSAGE_CODES as $codeMessage => $code) { + if (false !== stripos($message, $codeMessage)) { + return $code; + } + } + + /* If no code was matched, return the default one */ + return self::ERROR_UNDEFINED; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForCheckout.php b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForCheckout.php new file mode 100644 index 000000000000..4b2d1afdea00 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForCheckout.php @@ -0,0 +1,73 @@ +checkoutAllowance = $checkoutAllowance; + $this->getCartForUser = $getCartForUser; + } + + /** + * Gets the cart for the user validated and configured for guest checkout if applicable + * + * @param string $cartHash + * @param int|null $customerId + * @param int $storeId + * @return Quote + * @throws GraphQlAuthorizationException + * @throws GraphQlInputException + * @throws GraphQlNoSuchEntityException + */ + public function execute(string $cartHash, ?int $customerId, int $storeId): Quote + { + try { + $cart = $this->getCartForUser->execute($cartHash, $customerId, $storeId); + } catch (NoSuchEntityException $e) { + throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e); + } + $this->checkoutAllowance->execute($cart); + + if (null === $customerId || 0 === $customerId) { + if (!$cart->getCustomerEmail()) { + throw new GraphQlInputException(__("Guest email for cart is missing.")); + } + $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST); + } + + return $cart; + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php index 21df9465a08e..77a31cc3cd02 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/GetCartForUser.php @@ -7,16 +7,13 @@ namespace Magento\QuoteGraphQl\Model\Cart; -use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException; use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; -use Magento\Quote\Api\CartManagementInterface; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface; use Magento\Quote\Model\Quote; -use Magento\Store\Api\StoreRepositoryInterface; /** * Get cart @@ -34,31 +31,31 @@ class GetCartForUser private $cartRepository; /** - * @var CheckCartCheckoutAllowance + * @var IsActive */ - private $checkoutAllowance; + private $isActive; /** - * @var StoreRepositoryInterface + * @var UpdateCartCurrency */ - private $storeRepository; + private $updateCartCurrency; /** * @param MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId * @param CartRepositoryInterface $cartRepository - * @param CheckCartCheckoutAllowance $checkoutAllowance - * @param StoreRepositoryInterface $storeRepository + * @param IsActive $isActive + * @param UpdateCartCurrency $updateCartCurrency */ public function __construct( MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId, CartRepositoryInterface $cartRepository, - CheckCartCheckoutAllowance $checkoutAllowance, - StoreRepositoryInterface $storeRepository = null + IsActive $isActive, + UpdateCartCurrency $updateCartCurrency ) { $this->maskedQuoteIdToQuoteId = $maskedQuoteIdToQuoteId; $this->cartRepository = $cartRepository; - $this->checkoutAllowance = $checkoutAllowance; - $this->storeRepository = $storeRepository ?: ObjectManager::getInstance()->get(StoreRepositoryInterface::class); + $this->isActive = $isActive; + $this->updateCartCurrency = $updateCartCurrency; } /** @@ -77,26 +74,19 @@ 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) { + } catch (NoSuchEntityException $exception) { throw new GraphQlNoSuchEntityException( __('Could not find a cart with ID "%masked_cart_id"', ['masked_cart_id' => $cartHash]) ); } - if (false === (bool)$cart->getIsActive()) { + if (false === (bool)$this->isActive->execute($cart)) { throw new GraphQlNoSuchEntityException(__('The cart isn\'t active.')); } - $cart = $this->updateCartCurrency($cart, $storeId); + $cart = $this->updateCartCurrency->execute($cart, $storeId); $cartCustomerId = (int)$cart->getCustomerId(); @@ -115,68 +105,4 @@ public function execute(string $cartHash, ?int $customerId, int $storeId): Quote } return $cart; } - - /** - * Gets the cart for the user validated and configured for guest checkout if applicable - * - * @param string $cartHash - * @param int|null $customerId - * @param int $storeId - * @return Quote - * @throws GraphQlAuthorizationException - * @throws GraphQlInputException - * @throws GraphQlNoSuchEntityException - */ - public function getCartForCheckout(string $cartHash, ?int $customerId, int $storeId): Quote - { - try { - $cart = $this->execute($cartHash, $customerId, $storeId); - } catch (NoSuchEntityException $e) { - throw new GraphQlNoSuchEntityException(__($e->getMessage()), $e); - } - $this->checkoutAllowance->execute($cart); - - if ((null === $customerId || 0 === $customerId)) { - if (!$cart->getCustomerEmail()) { - throw new GraphQlInputException(__("Guest email for cart is missing.")); - } - $cart->setCheckoutMethod(CartManagementInterface::METHOD_GUEST); - } - - return $cart; - } - - /** - * Sets cart currency based on specified store. - * - * @param Quote $cart - * @param int $storeId - * @return Quote - * @throws GraphQlInputException - * @throws NoSuchEntityException - */ - private function updateCartCurrency(Quote $cart, int $storeId): Quote - { - $cartStore = $this->storeRepository->getById($cart->getStoreId()); - $currentCartCurrencyCode = $cartStore->getCurrentCurrency()->getCode(); - if ((int)$cart->getStoreId() !== $storeId) { - $newStore = $this->storeRepository->getById($storeId); - if ($cartStore->getWebsite() !== $newStore->getWebsite()) { - throw new GraphQlInputException( - __('Can\'t assign cart to store in different website.') - ); - } - $cart->setStoreId($storeId); - $cart->setStoreCurrencyCode($newStore->getCurrentCurrency()); - $cart->setQuoteCurrencyCode($newStore->getCurrentCurrency()); - } elseif ($cart->getQuoteCurrencyCode() !== $currentCartCurrencyCode) { - $cart->setQuoteCurrencyCode($cartStore->getCurrentCurrency()); - } else { - return $cart; - } - $this->cartRepository->save($cart); - $cart = $this->cartRepository->get($cart->getId()); - - return $cart; - } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/IsActive.php b/app/code/Magento/QuoteGraphQl/Model/Cart/IsActive.php new file mode 100644 index 000000000000..531d7ba11921 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/IsActive.php @@ -0,0 +1,27 @@ +getIsActive(); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/UpdateCartCurrency.php b/app/code/Magento/QuoteGraphQl/Model/Cart/UpdateCartCurrency.php new file mode 100644 index 000000000000..109ee7b4ef54 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/UpdateCartCurrency.php @@ -0,0 +1,74 @@ +cartRepository = $cartRepository; + $this->storeRepository = $storeRepository; + } + + /** + * Sets cart currency based on specified store. + * + * @param Quote $cart + * @param int $storeId + * @return Quote + * @throws GraphQlInputException|NoSuchEntityException|LocalizedException + */ + public function execute(Quote $cart, int $storeId): Quote + { + $cartStore = $this->storeRepository->getById($cart->getStoreId()); + $currentCartCurrencyCode = $cartStore->getCurrentCurrency()->getCode(); + if ((int)$cart->getStoreId() !== $storeId) { + $newStore = $this->storeRepository->getById($storeId); + if ($cartStore->getWebsite() !== $newStore->getWebsite()) { + throw new GraphQlInputException( + __('Can\'t assign cart to store in different website.') + ); + } + $cart->setStoreId($storeId); + $cart->setStoreCurrencyCode($newStore->getCurrentCurrency()); + $cart->setQuoteCurrencyCode($newStore->getCurrentCurrency()); + } elseif ($cart->getQuoteCurrencyCode() !== $currentCartCurrencyCode) { + $cart->setQuoteCurrencyCode($cartStore->getCurrentCurrency()); + } else { + return $cart; + } + $this->cartRepository->save($cart); + return $this->cartRepository->get($cart->getId()); + } +} diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php index b0fca63018e7..7cbc64a41d37 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php @@ -14,8 +14,8 @@ use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\GraphQl\Helper\Error\AggregateExceptionMessageFormatter; +use Magento\QuoteGraphQl\Model\Cart\GetCartForCheckout; use Magento\GraphQl\Model\Query\ContextInterface; -use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; use Magento\QuoteGraphQl\Model\Cart\PlaceOrder as PlaceOrderModel; use Magento\QuoteGraphQl\Model\Cart\PlaceOrderMutexInterface; use Magento\Sales\Api\OrderRepositoryInterface; @@ -26,9 +26,9 @@ class PlaceOrder implements ResolverInterface { /** - * @var GetCartForUser + * @var GetCartForCheckout */ - private $getCartForUser; + private $getCartForCheckout; /** * @var PlaceOrderModel @@ -51,20 +51,20 @@ class PlaceOrder implements ResolverInterface private $placeOrderMutex; /** - * @param GetCartForUser $getCartForUser + * @param GetCartForCheckout $getCartForCheckout * @param PlaceOrderModel $placeOrder * @param OrderRepositoryInterface $orderRepository * @param AggregateExceptionMessageFormatter $errorMessageFormatter * @param PlaceOrderMutexInterface|null $placeOrderMutex */ public function __construct( - GetCartForUser $getCartForUser, + GetCartForCheckout $getCartForCheckout, PlaceOrderModel $placeOrder, OrderRepositoryInterface $orderRepository, AggregateExceptionMessageFormatter $errorMessageFormatter, ?PlaceOrderMutexInterface $placeOrderMutex = null ) { - $this->getCartForUser = $getCartForUser; + $this->getCartForCheckout = $getCartForCheckout; $this->placeOrder = $placeOrder; $this->orderRepository = $orderRepository; $this->errorMessageFormatter = $errorMessageFormatter; @@ -104,7 +104,7 @@ private function run(Field $field, ContextInterface $context, ResolveInfo $info, $storeId = (int)$context->getExtensionAttributes()->getStore()->getId(); try { - $cart = $this->getCartForUser->getCartForCheckout($maskedCartId, $userId, $storeId); + $cart = $this->getCartForCheckout->execute($maskedCartId, $userId, $storeId); $orderId = $this->placeOrder->execute($cart, $maskedCartId, $userId); $order = $this->orderRepository->get($orderId); } catch (LocalizedException $e) { diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php index 500c2aa35999..1b9ee4ad3907 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/SetPaymentAndPlaceOrder.php @@ -15,7 +15,7 @@ use Magento\Framework\GraphQl\Exception\GraphQlNoSuchEntityException; use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; -use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; +use Magento\QuoteGraphQl\Model\Cart\GetCartForCheckout; use Magento\QuoteGraphQl\Model\Cart\SetPaymentAndPlaceOrder as SetPaymentAndPlaceOrderModel; use Magento\Sales\Api\OrderRepositoryInterface; @@ -29,9 +29,9 @@ class SetPaymentAndPlaceOrder implements ResolverInterface { /** - * @var GetCartForUser + * @var GetCartForCheckout */ - private $getCartForUser; + private $getCartForCheckout; /** * @var SetPaymentAndPlaceOrderModel @@ -44,16 +44,16 @@ class SetPaymentAndPlaceOrder implements ResolverInterface private $orderRepository; /** - * @param GetCartForUser $getCartForUser + * @param GetCartForCheckout $getCartForCheckout * @param SetPaymentAndPlaceOrderModel $setPaymentAndPlaceOrder * @param OrderRepositoryInterface $orderRepository */ public function __construct( - GetCartForUser $getCartForUser, + GetCartForCheckout $getCartForCheckout, SetPaymentAndPlaceOrderModel $setPaymentAndPlaceOrder, OrderRepositoryInterface $orderRepository ) { - $this->getCartForUser = $getCartForUser; + $this->getCartForCheckout = $getCartForCheckout; $this->setPaymentAndPlaceOrder = $setPaymentAndPlaceOrder; $this->orderRepository = $orderRepository; } @@ -78,7 +78,7 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value $storeId = (int)$context->getExtensionAttributes()->getStore()->getId(); try { - $cart = $this->getCartForUser->getCartForCheckout($maskedCartId, $userId, $storeId); + $cart = $this->getCartForCheckout->execute($maskedCartId, $userId, $storeId); $orderId = $this->setPaymentAndPlaceOrder->execute($cart, $maskedCartId, $userId, $paymentData); $order = $this->orderRepository->get($orderId); } catch (GraphQlInputException | GraphQlNoSuchEntityException | GraphQlAuthorizationException $e) { diff --git a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php index 2f4c097b1f02..9668f4e2239d 100644 --- a/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php +++ b/lib/internal/Magento/Framework/Api/SearchCriteria/CollectionProcessor/FilterProcessor.php @@ -140,7 +140,7 @@ private function checkFromTo(&$fields, &$conditions) $_fields = array_unique($fields); $_conditions = []; foreach ($conditions as $condition) { - $_conditions[array_key_first($condition)] = array_first($condition); + $_conditions[array_key_first($condition)] = reset($condition); } if ((count($_fields) == 1) && (count($_conditions) == 2) && isset($_conditions['from']) && isset($_conditions['to'])