diff --git a/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php b/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php index 005cf3a10ca8..f8d7844dd051 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php +++ b/app/code/Magento/QuoteGraphQl/Model/Cart/AddProductsToCart.php @@ -8,7 +8,6 @@ namespace Magento\QuoteGraphQl\Model\Cart; use Magento\Framework\GraphQl\Exception\GraphQlInputException; -use Magento\Framework\Message\AbstractMessage; use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Model\Quote; @@ -53,31 +52,6 @@ public function execute(Quote $cart, array $cartItems): void foreach ($cartItems as $cartItemData) { $this->addProductToCart->execute($cart, $cartItemData); } - - if ($cart->getData('has_error')) { - throw new GraphQlInputException( - __('Shopping cart error: %message', ['message' => $this->getCartErrors($cart)]) - ); - } - $this->cartRepository->save($cart); } - - /** - * Collecting cart errors - * - * @param Quote $cart - * @return string - */ - private function getCartErrors(Quote $cart): string - { - $errorMessages = []; - - /** @var AbstractMessage $error */ - foreach ($cart->getErrors() as $error) { - $errorMessages[] = $error->getText(); - } - - return implode(PHP_EOL, $errorMessages); - } } diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/CartMessages.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartMessages.php new file mode 100644 index 000000000000..df6ab78eac20 --- /dev/null +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/CartMessages.php @@ -0,0 +1,57 @@ +getData('has_error'))) { + return []; + } + return $this->getCartErrors($cart); + } + + /** + * Collecting cart errors + * + * @param Quote $cart + * @return array + */ + private function getCartErrors(Quote $cart): array + { + $errorMessages = []; + + /** @var AbstractMessage $error */ + foreach ($cart->getMessages() as $idettifier => $error) { + $errorMessages[] = [ + 'identifier' => $idettifier, + 'text' => $error->getText() + ]; + } + + return $errorMessages; + } +} diff --git a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls index d334d56c85aa..9439833eec7f 100644 --- a/app/code/Magento/QuoteGraphQl/etc/schema.graphqls +++ b/app/code/Magento/QuoteGraphQl/etc/schema.graphqls @@ -206,6 +206,7 @@ type Cart { prices: CartPrices @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartPrices") total_quantity: Float! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartTotalQuantity") is_virtual: Boolean! @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartIsVirtual") + messages: [Message] @resolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartMessages") @doc(description:"Return all shopping cart messages for a guest or logged in user") } interface CartAddressInterface @typeResolver(class: "\\Magento\\QuoteGraphQl\\Model\\Resolver\\CartAddressTypeResolver") { @@ -366,3 +367,8 @@ type Order { order_number: String! order_id: String @deprecated(reason: "The order_id field is deprecated, use order_number instead.") } + +type Message { + identifier: String + text: String +} diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CartMessagesTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CartMessagesTest.php new file mode 100644 index 000000000000..5faff232edaa --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Quote/CartMessagesTest.php @@ -0,0 +1,136 @@ +quoteResource = $objectManager->get(QuoteResource::class); + $this->quoteFactory = $objectManager->get(QuoteFactory::class); + $this->quoteIdToMaskedId = $objectManager->get(QuoteIdToMaskedQuoteIdInterface::class); + $this->getMaskedQuoteIdByReservedOrderId = $objectManager->get(GetMaskedQuoteIdByReservedOrderId::class); + $this->customerTokenService = $objectManager->get(CustomerTokenServiceInterface::class); + } + + /** + * @magentoApiDataFixture Magento/Checkout/_files/active_quote.php + */ + public function testCartWithoutErrors() + { + $maskedQuoteId = $this->getMaskedQuoteId(); + + $query = $this->getCartMessagesQuery($maskedQuoteId); + $response = $this->graphQlMutation($query); + self::assertEquals([], $response['cart']['messages']); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/customer/create_empty_cart.php + * @magentoApiDataFixture Magento/GraphQl/Quote/_files/add_simple_product.php + * @magentoApiDataFixture Magento/GraphQl/Catalog/_files/set_simple_product_out_of_stock.php + */ + public function testCartWithOutOfStockProduct() + { + $reservedOrderId = 'test_quote'; + $maskedQuoteId = $this->getMaskedQuoteIdByReservedOrderId->execute($reservedOrderId); + + $query = $this->getCartMessagesQuery($maskedQuoteId); + + $response = $this->graphQlMutation($query, [], '', $this->getHeaderMap()); + self::assertEquals('Some of the products are out of stock.', $response['cart']['messages'][0]['text']); + } + + /** + * @return string + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function getMaskedQuoteId() : string + { + $quote = $this->quoteFactory->create(); + $this->quoteResource->load($quote, 'test_order_1', 'reserved_order_id'); + + return $this->quoteIdToMaskedId->execute((int)$quote->getId()); + } + + /** + * @param string $maskedQuoteId + * @return string + */ + public function getCartMessagesQuery(string $maskedQuoteId): string + { + return <<customerTokenService->createCustomerAccessToken($username, $password); + $headerMap = ['Authorization' => 'Bearer ' . $customerToken]; + return $headerMap; + } +}