9
9
10
10
use Exception ;
11
11
use Magento \Catalog \Api \ProductRepositoryInterface ;
12
+ use Magento \Catalog \Model \Product ;
13
+ use Magento \Framework \DataObject ;
14
+ use Magento \Quote \Model \Quote \Item ;
15
+ use Magento \Catalog \Model \Product \Type \AbstractType ;
16
+ use Magento \Framework \Model \Context ;
17
+ use Magento \Framework \Event \ManagerInterface ;
18
+ use Magento \Framework \Phrase ;
19
+ use Magento \Framework \Exception \LocalizedException ;
12
20
use Magento \Framework \Exception \NoSuchEntityException ;
13
21
use Magento \Framework \GraphQl \Exception \GraphQlInputException ;
14
22
use Magento \Framework \GraphQl \Exception \GraphQlNoSuchEntityException ;
15
23
use Magento \Quote \Model \Quote ;
24
+ use Magento \Quote \Model \Quote \Item \Processor ;
16
25
use Magento \QuoteGraphQl \Model \Cart \BuyRequest \BuyRequestBuilder ;
26
+ use Magento \Framework \App \CacheInterface ;
17
27
18
28
/**
19
29
* Add simple product to cart mutation
@@ -30,16 +40,33 @@ class AddSimpleProductToCart
30
40
*/
31
41
private $ buyRequestBuilder ;
32
42
43
+ /**
44
+ * @var Processor
45
+ */
46
+ private $ itemProcessor ;
47
+
48
+ /**
49
+ * @var ManagerInterface
50
+ */
51
+ private $ eventManager ;
52
+
33
53
/**
34
54
* @param ProductRepositoryInterface $productRepository
35
55
* @param BuyRequestBuilder $buyRequestBuilder
56
+ * @param Processor $itemProcessor
57
+ * @param Context $context
36
58
*/
37
59
public function __construct (
38
60
ProductRepositoryInterface $ productRepository ,
39
- BuyRequestBuilder $ buyRequestBuilder
61
+ BuyRequestBuilder $ buyRequestBuilder ,
62
+ Processor $ itemProcessor ,
63
+ Context $ context ,
64
+ CacheInterface $ cache
40
65
) {
41
66
$ this ->productRepository = $ productRepository ;
42
67
$ this ->buyRequestBuilder = $ buyRequestBuilder ;
68
+ $ this ->itemProcessor = $ itemProcessor ;
69
+ $ this ->eventManager = $ context ->getEventDispatcher ();
43
70
}
44
71
45
72
/**
@@ -62,7 +89,11 @@ public function execute(Quote $cart, array $cartItemData): void
62
89
}
63
90
64
91
try {
65
- $ result = $ cart ->addProduct ($ product , $ this ->buyRequestBuilder ->build ($ cartItemData ));
92
+ $ result = $ this ->addProductToCartWithConcurrency (
93
+ $ cart ,
94
+ $ product ,
95
+ $ this ->buyRequestBuilder ->build ($ cartItemData )
96
+ );
66
97
} catch (Exception $ e ) {
67
98
throw new GraphQlInputException (
68
99
__ (
@@ -100,4 +131,79 @@ private function extractSku(array $cartItemData): string
100
131
}
101
132
return (string )$ cartItemData ['data ' ]['sku ' ];
102
133
}
134
+
135
+ /**
136
+ * @param Quote $cart
137
+ * @param Product $product
138
+ * @param DataObject $request
139
+ * @return Item
140
+ * @throws LocalizedException
141
+ */
142
+ private function addProductToCartWithConcurrency (Quote $ cart , Product $ product , DataObject $ request ) : Item
143
+ {
144
+ if (!$ product ->isSalable ()) {
145
+ throw new LocalizedException (
146
+ __ ('Product that you are trying to add is not available. ' )
147
+ );
148
+ }
149
+ $ cartCandidates = $ product ->getTypeInstance ()->prepareForCartAdvanced (
150
+ $ request ,
151
+ $ product ,
152
+ AbstractType::PROCESS_MODE_FULL
153
+ );
154
+ if (is_string ($ cartCandidates ) || $ cartCandidates instanceof Phrase) {
155
+ throw new LocalizedException ((string )$ cartCandidates );
156
+ }
157
+ if (!is_array ($ cartCandidates )) {
158
+ $ cartCandidates = [$ cartCandidates ];
159
+ }
160
+ $ parentItem = null ;
161
+ $ errors = [];
162
+ $ items = [];
163
+ foreach ($ cartCandidates as $ candidate ) {
164
+ $ stickWithinParent = $ candidate ->getParentProductId () ? $ parentItem : null ;
165
+ $ candidate ->setStickWithinParent ($ stickWithinParent );
166
+ $ item = null ;
167
+ $ itemsCollection = $ cart ->getItemsCollection (false );
168
+
169
+ foreach ($ itemsCollection as $ item ) {
170
+ if (!$ item ->isDeleted () && $ item ->representProduct ($ product )) {
171
+ break ;
172
+ }
173
+ }
174
+
175
+ if (!$ item ) {
176
+ $ item = $ this ->itemProcessor ->init ($ candidate , $ request );
177
+ $ item ->setQuote ($ cart );
178
+ $ item ->setOptions ($ candidate ->getCustomOptions ());
179
+ $ item ->setProduct ($ candidate );
180
+ $ cart ->addItem ($ item );
181
+ }
182
+ $ items [] = $ item ;
183
+
184
+ if (!$ parentItem ) {
185
+ $ parentItem = $ item ;
186
+ }
187
+ if ($ parentItem && $ candidate ->getParentProductId () && !$ item ->getParentItem ()) {
188
+ $ item ->setParentItem ($ parentItem );
189
+ }
190
+
191
+ $ this ->itemProcessor ->prepare ($ item , $ request , $ candidate );
192
+
193
+ if ($ item ->getHasError ()) {
194
+ $ cart ->deleteItem ($ item );
195
+ foreach ($ item ->getMessage (false ) as $ message ) {
196
+ if (!in_array ($ message , $ errors )) {
197
+ $ errors [] = $ message ;
198
+ }
199
+ }
200
+ break ;
201
+ }
202
+ }
203
+ if (!empty ($ errors )) {
204
+ throw new LocalizedException (__ (implode ("\n" , $ errors )));
205
+ }
206
+ $ this ->eventManager ->dispatch ('sales_quote_product_add_after ' , ['items ' => $ items ]);
207
+ return $ parentItem ;
208
+ }
103
209
}
0 commit comments