7
7
8
8
namespace Magento \InventorySales \Test \Integration \StockManagement ;
9
9
10
+ use Magento \Catalog \Api \Data \ProductInterface ;
10
11
use Magento \Catalog \Api \ProductRepositoryInterface ;
11
- use Magento \CatalogInventory \Model \StockManagement ;
12
- use Magento \InventoryApi \Api \StockRepositoryInterface ;
12
+ use Magento \Framework \Api \SearchCriteriaBuilder ;
13
+ use Magento \Framework \App \ResourceConnection ;
14
+ use Magento \Framework \Registry ;
13
15
use Magento \InventoryReservations \Model \CleanupReservationsInterface ;
16
+ use Magento \InventoryReservations \Model \GetReservationsQuantityInterface ;
14
17
use Magento \InventoryReservationsApi \Api \AppendReservationsInterface ;
18
+ use Magento \InventoryReservationsApi \Api \Data \ReservationInterface ;
15
19
use Magento \InventoryReservationsApi \Api \ReservationBuilderInterface ;
20
+ use Magento \InventorySalesApi \Api \Data \SalesEventInterface ;
16
21
use Magento \InventorySalesApi \Api \GetProductSalableQtyInterface ;
17
- use Magento \Store \Api \WebsiteRepositoryInterface ;
22
+ use Magento \Quote \Api \CartManagementInterface ;
23
+ use Magento \Quote \Api \CartRepositoryInterface ;
24
+ use Magento \Quote \Api \Data \CartInterface ;
25
+ use Magento \Quote \Api \Data \CartItemInterface ;
26
+ use Magento \Quote \Api \Data \CartItemInterfaceFactory ;
27
+ use Magento \Sales \Api \OrderManagementInterface ;
28
+ use Magento \Sales \Api \OrderRepositoryInterface ;
29
+ use Magento \Store \Model \StoreManagerInterface ;
18
30
use Magento \TestFramework \Helper \Bootstrap ;
19
31
use PHPUnit \Framework \TestCase ;
20
32
33
+ /**
34
+ * Tests correct Product Salable Quantity decreasing after Order placing.
35
+ *
36
+ * @magentoAppIsolation enabled
37
+ * @magentoDbIsolation enabled
38
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
39
+ */
21
40
class ReservationPlacingDuringRegisterProductsSaleTest extends TestCase
22
41
{
42
+ /**
43
+ * @var AppendReservationsInterface
44
+ */
45
+ private $ appendReservations ;
46
+
47
+ /**
48
+ * @var CartItemInterfaceFactory
49
+ */
50
+ private $ cartItemFactory ;
51
+
52
+ /**
53
+ * @var CartManagementInterface
54
+ */
55
+ private $ cartManagement ;
56
+
57
+ /**
58
+ * @var CartRepositoryInterface
59
+ */
60
+ private $ cartRepository ;
61
+
62
+ /**
63
+ * @var CleanupReservationsInterface
64
+ */
65
+ private $ cleanupReservations ;
66
+
23
67
/**
24
68
* @var GetProductSalableQtyInterface
25
69
*/
26
70
private $ getProductSalableQty ;
27
71
28
72
/**
29
- * @var ProductRepositoryInterface
73
+ * @var GetReservationsQuantityInterface
30
74
*/
31
- private $ productRepository ;
75
+ private $ getReservationsQuantity ;
76
+
77
+ /**
78
+ * @var OrderManagementInterface
79
+ */
80
+ private $ orderManagement ;
81
+
82
+ /**
83
+ * @var OrderRepositoryInterface
84
+ */
85
+ private $ orderRepository ;
32
86
33
87
/**
34
- * @var StockRepositoryInterface
88
+ * @var ProductRepositoryInterface
35
89
*/
36
- private $ stockRepository ;
90
+ private $ productRepository ;
37
91
38
92
/**
39
- * @var WebsiteRepositoryInterface
93
+ * @var Registry
40
94
*/
41
- private $ websiteRepository ;
95
+ private $ registry ;
42
96
43
97
/**
44
98
* @var ReservationBuilderInterface
45
99
*/
46
100
private $ reservationBuilder ;
47
101
48
102
/**
49
- * @var AppendReservationsInterface
103
+ * @var ResourceConnection
50
104
*/
51
- private $ appendReservations ;
105
+ private $ resourceConnection ;
52
106
53
107
/**
54
- * @var CleanupReservationsInterface
108
+ * @var SearchCriteriaBuilder
55
109
*/
56
- private $ cleanupReservations ;
110
+ private $ searchCriteriaBuilder ;
57
111
58
112
/**
59
- * @var StockManagement
113
+ * @var StoreManagerInterface
60
114
*/
61
- private $ stockManagement ;
115
+ private $ storeManager ;
62
116
63
117
protected function setUp ()
64
118
{
119
+ $ this ->appendReservations = Bootstrap::getObjectManager ()->get (AppendReservationsInterface::class);
120
+ $ this ->cartItemFactory = Bootstrap::getObjectManager ()->get (CartItemInterfaceFactory::class);
121
+ $ this ->cartManagement = Bootstrap::getObjectManager ()->get (CartManagementInterface::class);
122
+ $ this ->cartRepository = Bootstrap::getObjectManager ()->get (CartRepositoryInterface::class);
123
+ $ this ->cleanupReservations = Bootstrap::getObjectManager ()->get (CleanupReservationsInterface::class);
65
124
$ this ->getProductSalableQty = Bootstrap::getObjectManager ()->get (GetProductSalableQtyInterface::class);
125
+ $ this ->getReservationsQuantity = Bootstrap::getObjectManager ()->get (GetReservationsQuantityInterface::class);
126
+ $ this ->orderManagement = Bootstrap::getObjectManager ()->get (OrderManagementInterface::class);
127
+ $ this ->orderRepository = Bootstrap::getObjectManager ()->get (OrderRepositoryInterface::class);
66
128
$ this ->productRepository = Bootstrap::getObjectManager ()->get (ProductRepositoryInterface::class);
67
- $ this ->stockRepository = Bootstrap::getObjectManager ()->get (StockRepositoryInterface::class);
68
- $ this ->websiteRepository = Bootstrap::getObjectManager ()->get (WebsiteRepositoryInterface::class);
129
+ $ this ->registry = Bootstrap::getObjectManager ()->get (Registry::class);
69
130
$ this ->reservationBuilder = Bootstrap::getObjectManager ()->get (ReservationBuilderInterface::class);
70
- $ this ->appendReservations = Bootstrap::getObjectManager ()->get (AppendReservationsInterface ::class);
71
- $ this ->cleanupReservations = Bootstrap::getObjectManager ()->get (CleanupReservationsInterface ::class);
72
- $ this ->stockManagement = Bootstrap::getObjectManager ()->get (StockManagement ::class);
131
+ $ this ->resourceConnection = Bootstrap::getObjectManager ()->get (ResourceConnection ::class);
132
+ $ this ->searchCriteriaBuilder = Bootstrap::getObjectManager ()->get (SearchCriteriaBuilder ::class);
133
+ $ this ->storeManager = Bootstrap::getObjectManager ()->get (StoreManagerInterface ::class);
73
134
}
74
135
75
136
/**
@@ -81,6 +142,8 @@ protected function tearDown()
81
142
}
82
143
83
144
/**
145
+ * Tests correct Product Salable Quantity decreasing after Order placing.
146
+ *
84
147
* @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/products.php
85
148
* @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/sources.php
86
149
* @magentoDataFixture ../../../../app/code/Magento/InventoryApi/Test/_files/stocks.php
@@ -89,21 +152,114 @@ protected function tearDown()
89
152
* @magentoDataFixture ../../../../app/code/Magento/InventoryIndexer/Test/_files/reindex_inventory.php
90
153
* @magentoDataFixture ../../../../app/code/Magento/InventorySalesApi/Test/_files/websites_with_stores.php
91
154
* @magentoDataFixture ../../../../app/code/Magento/InventorySalesApi/Test/_files/stock_website_sales_channels.php
155
+ * @magentoDataFixture ../../../../app/code/Magento/InventorySalesApi/Test/_files/quote.php
92
156
*/
93
157
public function testRegisterProductsSale ()
94
158
{
95
- $ this ->markTestSkipped ('https://github.com/magento-engcom/msi/issues/918 ' );
159
+ $ this ->storeManager ->setCurrentStore ('store_for_eu_website ' );
160
+ $ sku = 'SKU-1 ' ;
161
+ $ quoteItemQty = 3.5 ;
162
+
163
+ $ cart = $ this ->getCart ();
164
+ $ product = $ this ->productRepository ->get ($ sku );
165
+ $ cartItem = $ this ->getCartItem ($ product , $ quoteItemQty , (int )$ cart ->getId ());
166
+ $ cart ->addItem ($ cartItem );
167
+ $ this ->cartRepository ->save ($ cart );
168
+
96
169
self ::assertEquals (8.5 , $ this ->getProductSalableQty ->execute ('SKU-1 ' , 10 ));
170
+ self ::assertEquals (0 , $ this ->getReservationsQuantity ->execute ('SKU-1 ' , 10 ));
97
171
98
- $ product = $ this ->productRepository ->get ('SKU-1 ' );
99
- $ website = $ this ->websiteRepository ->get ('eu_website ' );
100
- $ this ->stockManagement ->registerProductsSale ([$ product ->getId () => 3.5 ], $ website ->getId ());
172
+ $ orderId = $ this ->cartManagement ->placeOrder ($ cart ->getId ());
101
173
102
174
self ::assertEquals (5 , $ this ->getProductSalableQty ->execute ('SKU-1 ' , 10 ));
175
+ self ::assertEquals (-3.5 , $ this ->getReservationsQuantity ->execute ('SKU-1 ' , 10 ));
176
+ self ::assertEquals (
177
+ sprintf (
178
+ '%s:%s:%d ' ,
179
+ SalesEventInterface::EVENT_ORDER_PLACED ,
180
+ SalesEventInterface::OBJECT_TYPE_ORDER ,
181
+ $ orderId
182
+ ),
183
+ $ this ->getReservationMetadata ()
184
+ );
185
+
186
+ //cleanup
187
+ $ this ->deleteOrderById ((int )$ orderId );
188
+ }
189
+
190
+ /**
191
+ * Get Cart for placing Order.
192
+ *
193
+ * @return CartInterface
194
+ */
195
+ private function getCart (): CartInterface
196
+ {
197
+ $ searchCriteria = $ this ->searchCriteriaBuilder
198
+ ->addFilter ('reserved_order_id ' , 'test_order_1 ' )
199
+ ->create ();
200
+ /** @var CartInterface $cart */
201
+ $ cart = current ($ this ->cartRepository ->getList ($ searchCriteria )->getItems ());
202
+ $ cart ->setStoreId (1 );
103
203
104
- $ this ->appendReservations ->execute ([
105
- // unreserved 3.5 units for cleanup
106
- $ this ->reservationBuilder ->setStockId (10 )->setSku ('SKU-1 ' )->setQuantity (3.5 )->build (),
107
- ]);
204
+ return $ cart ;
205
+ }
206
+
207
+ /**
208
+ * Create Cart Item from Product and Quantity.
209
+ *
210
+ * @param ProductInterface $product
211
+ * @param float $quoteItemQty
212
+ * @param int $cartId
213
+ * @return CartItemInterface
214
+ */
215
+ private function getCartItem (ProductInterface $ product , float $ quoteItemQty , int $ cartId ): CartItemInterface
216
+ {
217
+ /** @var CartItemInterface $cartItem */
218
+ $ cartItem = $ this ->cartItemFactory ->create (
219
+ [
220
+ 'data ' => [
221
+ CartItemInterface::KEY_SKU => $ product ->getSku (),
222
+ CartItemInterface::KEY_QTY => $ quoteItemQty ,
223
+ CartItemInterface::KEY_QUOTE_ID => $ cartId ,
224
+ 'product_id ' => $ product ->getId (),
225
+ 'product ' => $ product ,
226
+ ]
227
+ ]
228
+ );
229
+
230
+ return $ cartItem ;
231
+ }
232
+
233
+ /**
234
+ * Rollback created Order.
235
+ *
236
+ * @param int $orderId
237
+ */
238
+ private function deleteOrderById (int $ orderId )
239
+ {
240
+ $ this ->registry ->unregister ('isSecureArea ' );
241
+ $ this ->registry ->register ('isSecureArea ' , true );
242
+ $ this ->orderManagement ->cancel ($ orderId );
243
+ $ this ->orderRepository ->delete ($ this ->orderRepository ->get ($ orderId ));
244
+ $ this ->registry ->unregister ('isSecureArea ' );
245
+ $ this ->registry ->register ('isSecureArea ' , false );
246
+ }
247
+
248
+ /**
249
+ * Get "metadata" field value of last created Inventory Reservation.
250
+ *
251
+ * @return string
252
+ */
253
+ private function getReservationMetadata (): string
254
+ {
255
+ $ connection = $ this ->resourceConnection ->getConnection ();
256
+ $ select = $ connection ->select ()->from (
257
+ ['inventory_reservation ' => $ this ->resourceConnection ->getTableName ('inventory_reservation ' )],
258
+ ['metadata ' ]
259
+ )->order (
260
+ ReservationInterface::RESERVATION_ID . ' DESC '
261
+ );
262
+ $ result = $ connection ->fetchOne ($ select );
263
+ return $ result ;
108
264
}
109
265
}
0 commit comments