99
1010use Magento \Framework \Exception \AuthorizationException ;
1111use Magento \Framework \Exception \LocalizedException ;
12+ use Magento \Framework \Exception \NoSuchEntityException ;
1213use Magento \Framework \GraphQl \Config \Element \Field ;
1314use Magento \Framework \GraphQl \Exception \GraphQlAuthorizationException ;
1415use Magento \Framework \GraphQl \Exception \GraphQlInputException ;
1516use Magento \Framework \GraphQl \Query \ResolverInterface ;
1617use Magento \Framework \GraphQl \Schema \Type \ResolveInfo ;
17- use Magento \GraphQl \ Helper \ Error \ AggregateExceptionMessageFormatter ;
18+ use Magento \Framework \ ObjectManager \ ResetAfterRequestInterface ;
1819use Magento \QuoteGraphQl \Model \Cart \GetCartForCheckout ;
19- use Magento \GraphQl \Model \Query \ContextInterface ;
2020use Magento \QuoteGraphQl \Model \Cart \PlaceOrder as PlaceOrderModel ;
2121use Magento \Sales \Api \OrderRepositoryInterface ;
2222
2323/**
2424 * Resolver for placing order after payment method has already been set
2525 */
26- class PlaceOrder implements ResolverInterface
26+ class PlaceOrder implements ResolverInterface, ResetAfterRequestInterface
2727{
28+ /**#@+
29+ * Error message codes
30+ */
31+ private const ERROR_CART_NOT_FOUND = 'CART_NOT_FOUND ' ;
32+ private const ERROR_CART_NOT_ACTIVE = 'CART_NOT_ACTIVE ' ;
33+ private const ERROR_GUEST_EMAIL_MISSING = 'GUEST_EMAIL_MISSING ' ;
34+ private const ERROR_UNABLE_TO_PLACE_ORDER = 'UNABLE_TO_PLACE_ORDER ' ;
35+ private const ERROR_UNDEFINED = 'UNDEFINED ' ;
36+ /**#@-*/
37+
38+ /**
39+ * List of error messages and codes.
40+ */
41+ private const MESSAGE_CODES = [
42+ 'Could not find a cart with ID ' => self ::ERROR_CART_NOT_FOUND ,
43+ 'The cart isn \'t active ' => self ::ERROR_CART_NOT_ACTIVE ,
44+ 'Guest email for cart is missing ' => self ::ERROR_GUEST_EMAIL_MISSING ,
45+ 'A server error stopped your order from being placed. Please try to place your order again ' =>
46+ self ::ERROR_UNABLE_TO_PLACE_ORDER ,
47+ 'Some addresses can \'t be used due to the configurations for specific countries ' =>
48+ self ::ERROR_UNABLE_TO_PLACE_ORDER ,
49+ 'The shipping method is missing. Select the shipping method and try again ' =>
50+ self ::ERROR_UNABLE_TO_PLACE_ORDER ,
51+ 'Please check the billing address information ' => self ::ERROR_UNABLE_TO_PLACE_ORDER ,
52+ 'Enter a valid payment method and try again ' => self ::ERROR_UNABLE_TO_PLACE_ORDER ,
53+ 'Some of the products are out of stock ' => self ::ERROR_UNABLE_TO_PLACE_ORDER ,
54+ ];
55+
2856 /**
2957 * @var GetCartForCheckout
3058 */
@@ -41,33 +69,32 @@ class PlaceOrder implements ResolverInterface
4169 private $ orderRepository ;
4270
4371 /**
44- * @var AggregateExceptionMessageFormatter
72+ * @var \string[]
4573 */
46- private $ errorMessageFormatter ;
74+ private $ errors = [] ;
4775
4876 /**
4977 * @param GetCartForCheckout $getCartForCheckout
5078 * @param PlaceOrderModel $placeOrder
5179 * @param OrderRepositoryInterface $orderRepository
52- * @param AggregateExceptionMessageFormatter $errorMessageFormatter
5380 */
5481 public function __construct (
5582 GetCartForCheckout $ getCartForCheckout ,
5683 PlaceOrderModel $ placeOrder ,
57- OrderRepositoryInterface $ orderRepository ,
58- AggregateExceptionMessageFormatter $ errorMessageFormatter
84+ OrderRepositoryInterface $ orderRepository
5985 ) {
6086 $ this ->getCartForCheckout = $ getCartForCheckout ;
6187 $ this ->placeOrder = $ placeOrder ;
6288 $ this ->orderRepository = $ orderRepository ;
63- $ this ->errorMessageFormatter = $ errorMessageFormatter ;
6489 }
6590
6691 /**
6792 * @inheritdoc
6893 */
6994 public function resolve (Field $ field , $ context , ResolveInfo $ info , array $ value = null , array $ args = null )
7095 {
96+ $ this ->errors = [];
97+ $ order = null ;
7198 if (empty ($ args ['input ' ]['cart_id ' ])) {
7299 throw new GraphQlInputException (__ ('Required parameter "cart_id" is missing ' ));
73100 }
@@ -80,28 +107,77 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value
80107 $ cart = $ this ->getCartForCheckout ->execute ($ maskedCartId , $ userId , $ storeId );
81108 $ orderId = $ this ->placeOrder ->execute ($ cart , $ maskedCartId , $ userId );
82109 $ order = $ this ->orderRepository ->get ($ orderId );
110+ } catch (NoSuchEntityException $ exception ) {
111+ $ this ->addError ($ exception ->getMessage ());
112+ } catch (GraphQlInputException $ exception ) {
113+ $ this ->addError ($ exception ->getMessage ());
83114 } catch (AuthorizationException $ exception ) {
84115 throw new GraphQlAuthorizationException (
85116 __ ($ exception ->getMessage ())
86117 );
87118 } catch (LocalizedException $ e ) {
88- throw $ this ->errorMessageFormatter ->getFormatted (
89- $ e ,
90- __ ('Unable to place order: A server error stopped your order from being placed. ' .
91- 'Please try to place your order again ' ),
92- 'Unable to place order ' ,
93- $ field ,
94- $ context ,
95- $ info
96- );
119+ $ this ->addError ($ e ->getMessage ());
120+ }
121+ if ($ this ->errors ) {
122+ return [
123+ 'errors ' =>
124+ $ this ->errors
125+ ];
97126 }
98-
99127 return [
100128 'order ' => [
101129 'order_number ' => $ order ->getIncrementId (),
102130 // @deprecated The order_id field is deprecated, use order_number instead
103131 'order_id ' => $ order ->getIncrementId (),
104132 ],
133+ 'errors ' => []
134+ ];
135+ }
136+
137+ /**
138+ * Add order line item error
139+ *
140+ * @param string $message
141+ * @return void
142+ */
143+ private function addError (string $ message ): void
144+ {
145+ $ this ->errors [] = [
146+ 'message ' => $ message ,
147+ 'code ' => $ this ->getErrorCode ($ message )
105148 ];
106149 }
150+
151+ /**
152+ * Get message error code. Ad-hoc solution based on message parsing.
153+ *
154+ * @param string $message
155+ * @return string
156+ */
157+ private function getErrorCode (string $ message ): string
158+ {
159+ $ code = self ::ERROR_UNDEFINED ;
160+
161+ $ matchedCodes = array_filter (
162+ self ::MESSAGE_CODES ,
163+ function ($ key ) use ($ message ) {
164+ return false !== strpos ($ message , $ key );
165+ },
166+ ARRAY_FILTER_USE_KEY
167+ );
168+
169+ if (!empty ($ matchedCodes )) {
170+ $ code = current ($ matchedCodes );
171+ }
172+
173+ return $ code ;
174+ }
175+
176+ /**
177+ * @inheritDoc
178+ */
179+ public function _resetState (): void
180+ {
181+ $ this ->errors = [];
182+ }
107183}
0 commit comments