6
6
declare (strict_types=1 );
7
7
namespace Magento \Sales \Model \Reorder ;
8
8
9
+ use Magento \Catalog \Api \Data \ProductInterface ;
9
10
use Magento \Catalog \Api \ProductRepositoryInterface ;
10
11
use Magento \Catalog \Model \Product ;
12
+ use Magento \Catalog \Model \ResourceModel \Product \Collection ;
11
13
use Magento \Framework \Exception \InputException ;
12
14
use Magento \Framework \Exception \NoSuchEntityException ;
13
15
use Magento \Quote \Api \CartRepositoryInterface ;
14
16
use Magento \Quote \Api \Data \CartInterface ;
15
17
use Magento \Quote \Model \Cart \CustomerCartResolver ;
18
+ use Magento \Quote \Model \Quote as Quote ;
19
+ use Magento \Sales \Api \Data \OrderItemInterface ;
16
20
use Magento \Sales \Helper \Reorder as ReorderHelper ;
17
21
use Magento \Sales \Model \Order \Item ;
18
22
use Magento \Sales \Model \OrderFactory ;
23
+ use Magento \Sales \Model \ResourceModel \Order \Item \Collection as ItemCollection ;
24
+ use Magento \Catalog \Model \ResourceModel \Product \CollectionFactory as ProductCollectionFactory ;
19
25
20
26
/**
21
27
* Allows customer quickly to reorder previously added products and put them to the Cart
@@ -81,28 +87,36 @@ class Reorder
81
87
*/
82
88
private $ customerCartProvider ;
83
89
90
+ /**
91
+ * @var ProductCollectionFactory
92
+ */
93
+ private $ productCollectionFactory ;
94
+
84
95
/**
85
96
* @param OrderFactory $orderFactory
86
97
* @param CustomerCartResolver $customerCartProvider
87
98
* @param CartRepositoryInterface $cartRepository
88
99
* @param ProductRepositoryInterface $productRepository
89
100
* @param ReorderHelper $reorderHelper
90
101
* @param \Psr\Log\LoggerInterface $logger
102
+ * @param ProductCollectionFactory $productCollectionFactory
91
103
*/
92
104
public function __construct (
93
105
OrderFactory $ orderFactory ,
94
106
CustomerCartResolver $ customerCartProvider ,
95
107
CartRepositoryInterface $ cartRepository ,
96
108
ProductRepositoryInterface $ productRepository ,
97
109
ReorderHelper $ reorderHelper ,
98
- \Psr \Log \LoggerInterface $ logger
110
+ \Psr \Log \LoggerInterface $ logger ,
111
+ ProductCollectionFactory $ productCollectionFactory
99
112
) {
100
113
$ this ->orderFactory = $ orderFactory ;
101
114
$ this ->cartRepository = $ cartRepository ;
102
115
$ this ->productRepository = $ productRepository ;
103
116
$ this ->reorderHelper = $ reorderHelper ;
104
117
$ this ->logger = $ logger ;
105
118
$ this ->customerCartProvider = $ customerCartProvider ;
119
+ $ this ->productCollectionFactory = $ productCollectionFactory ;
106
120
}
107
121
108
122
/**
@@ -133,10 +147,7 @@ public function execute(string $orderNumber, string $storeId): Data\ReorderOutpu
133
147
return $ this ->prepareOutput ($ cart );
134
148
}
135
149
136
- $ items = $ order ->getItemsCollection ();
137
- foreach ($ items as $ item ) {
138
- $ this ->addOrderItem ($ cart , $ item );
139
- }
150
+ $ this ->addItemsToCart ($ cart , $ order ->getItemsCollection (), $ storeId );
140
151
141
152
try {
142
153
$ this ->cartRepository ->save ($ cart );
@@ -145,52 +156,109 @@ public function execute(string $orderNumber, string $storeId): Data\ReorderOutpu
145
156
$ this ->addError ($ e ->getMessage ());
146
157
}
147
158
148
- $ cart = $ this ->cartRepository ->get ($ cart ->getId ());
159
+ $ savedCart = $ this ->cartRepository ->get ($ cart ->getId ());
149
160
150
- return $ this ->prepareOutput ($ cart );
161
+ return $ this ->prepareOutput ($ savedCart );
151
162
}
152
163
153
164
/**
154
- * Convert order item to quote item
165
+ * Add collections of order items to cart.
155
166
*
156
- * @param \Magento\Quote\Model\Quote $cart
157
- * @param Item $orderItem
167
+ * @param Quote $cart
168
+ * @param ItemCollection $orderItems
169
+ * @param string $storeId
158
170
* @return void
159
171
*/
160
- private function addOrderItem ( \ Magento \ Quote \ Model \ Quote $ cart , $ orderItem ): void
172
+ private function addItemsToCart ( Quote $ cart , ItemCollection $ orderItems , string $ storeId ): void
161
173
{
162
- /* @var $orderItem Item */
163
- if ($ orderItem ->getParentItem () === null ) {
164
- $ info = $ orderItem ->getProductOptionByCode ('info_buyRequest ' );
165
- $ info = new \Magento \Framework \DataObject ($ info );
166
- $ info ->setQty ($ orderItem ->getQtyOrdered ());
167
-
168
- try {
169
- /** @var Product $product */
170
- $ product = $ this ->productRepository ->getById ($ orderItem ->getProductId (), false , null , true );
171
- } catch (NoSuchEntityException $ e ) {
174
+ $ orderItemProductIds = [];
175
+ /** @var \Magento\Sales\Model\Order\Item[] $orderItemsByProductId */
176
+ $ orderItemsByProductId = [];
177
+
178
+ /** @var \Magento\Sales\Model\Order\Item $item */
179
+ foreach ($ orderItems as $ item ) {
180
+ if ($ item ->getParentItem () === null ) {
181
+ $ orderItemProductIds [] = $ item ->getProductId ();
182
+ $ orderItemsByProductId [$ item ->getProductId ()][$ item ->getId ()] = $ item ;
183
+ }
184
+ }
185
+
186
+ $ products = $ this ->getOrderProducts ($ storeId , $ orderItemProductIds );
187
+
188
+ // compare founded products and throw an error if some product not exists
189
+ $ productsNotFound = array_diff ($ orderItemProductIds , array_keys ($ products ));
190
+ if (!empty ($ productsNotFound )) {
191
+ foreach ($ productsNotFound as $ productId ) {
192
+ /** @var \Magento\Sales\Model\Order\Item $orderItemProductNotFound */
172
193
$ this ->addError (
173
- (string )__ ('Could not find a product with ID "%1" ' , $ orderItem -> getProductId () ),
194
+ (string )__ ('Could not find a product with ID "%1" ' , $ productId ),
174
195
self ::ERROR_PRODUCT_NOT_FOUND
175
196
);
176
- return ;
177
197
}
178
- $ addProductResult = null ;
179
- try {
180
- $ addProductResult = $ cart ->addProduct ($ product , $ info );
181
- } catch (\Magento \Framework \Exception \LocalizedException $ e ) {
182
- $ this ->addError ($ this ->getCartItemErrorMessage ($ orderItem , $ product , $ e ->getMessage ()));
183
- } catch (\Throwable $ e ) {
184
- $ this ->logger ->critical ($ e );
185
- $ this ->addError ($ this ->getCartItemErrorMessage ($ orderItem , $ product ), self ::ERROR_UNDEFINED );
198
+ }
199
+
200
+ foreach ($ orderItemsByProductId as $ productId => $ orderItems ) {
201
+ if (!isset ($ products [$ productId ])) {
202
+ continue ;
203
+ }
204
+ $ product = $ products [$ productId ];
205
+ foreach ($ orderItems as $ orderItem ) {
206
+ $ this ->addItemToCart ($ orderItem , $ cart , clone $ product );
186
207
}
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Get order products by store id and order item product ids.
213
+ *
214
+ * @param string $storeId
215
+ * @param int[] $orderItemProductIds
216
+ * @return Product[]
217
+ * @throws \Magento\Framework\Exception\LocalizedException
218
+ */
219
+ private function getOrderProducts (string $ storeId , array $ orderItemProductIds ): array
220
+ {
221
+ /** @var Collection $collection */
222
+ $ collection = $ this ->productCollectionFactory ->create ();
223
+ $ collection ->setStore ($ storeId )
224
+ ->addIdFilter ($ orderItemProductIds )
225
+ ->addStoreFilter ()
226
+ ->addAttributeToSelect ('* ' )
227
+ ->joinAttribute ('status ' , 'catalog_product/status ' , 'entity_id ' , null , 'inner ' )
228
+ ->joinAttribute ('visibility ' , 'catalog_product/visibility ' , 'entity_id ' , null , 'inner ' );
229
+
230
+ return $ collection ->getItems ();
231
+ }
232
+
233
+ /**
234
+ * Adds order item product to cart.
235
+ *
236
+ * @param OrderItemInterface $orderItem
237
+ * @param Quote $cart
238
+ * @param ProductInterface $product
239
+ * @return void
240
+ */
241
+ private function addItemToCart (OrderItemInterface $ orderItem , Quote $ cart , ProductInterface $ product ): void
242
+ {
243
+ $ info = $ orderItem ->getProductOptionByCode ('info_buyRequest ' );
244
+ $ info = new \Magento \Framework \DataObject ($ info );
245
+ $ info ->setQty ($ orderItem ->getQtyOrdered ());
246
+
247
+ $ addProductResult = null ;
248
+ try {
249
+ $ addProductResult = $ cart ->addProduct ($ product , $ info );
250
+ } catch (\Magento \Framework \Exception \LocalizedException $ e ) {
251
+ $ this ->addError ($ this ->getCartItemErrorMessage ($ orderItem , $ product , $ e ->getMessage ()));
252
+ } catch (\Throwable $ e ) {
253
+ $ this ->logger ->critical ($ e );
254
+ $ this ->addError ($ this ->getCartItemErrorMessage ($ orderItem , $ product ), self ::ERROR_UNDEFINED );
255
+ }
187
256
188
- // error happens in case the result is string
189
- if (is_string ($ addProductResult )) {
190
- $ errors = array_unique (explode ("\n" , $ addProductResult ));
191
- foreach ($ errors as $ error ) {
192
- $ this ->addError ($ this ->getCartItemErrorMessage ($ orderItem , $ product , $ error ));
193
- }
257
+ // error happens in case the result is string
258
+ if (is_string ($ addProductResult )) {
259
+ $ errors = array_unique (explode ("\n" , $ addProductResult ));
260
+ foreach ($ errors as $ error ) {
261
+ $ this ->addError ($ this ->getCartItemErrorMessage ($ orderItem , $ product , $ error ));
194
262
}
195
263
}
196
264
}
0 commit comments