Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
NegativeMinQtyPlaceOrderTest.php
Go to the documentation of this file.
1 <?php
6 declare(strict_types=1);
7 
9 
27 use Magento\Quote\Api\Data\CartItemInterfaceFactory;
34 use PHPUnit\Framework\TestCase;
35 
40 class NegativeMinQtyPlaceOrderTest extends TestCase
41 {
45  private $isProductSalableForRequestedQty;
46 
50  private $getProductSalableQty;
51 
55  private $getStockItemConfiguration;
56 
60  private $saveStockItemConfiguration;
61 
65  private $searchCriteriaBuilder;
66 
70  private $cartRepository;
71 
75  private $cleanupReservations;
76 
80  private $productRepository;
81 
85  private $cartManagement;
86 
90  private $cartItemFactory;
91 
95  private $stockRepository;
96 
100  private $storeRepository;
101 
105  private $orderRepository;
106 
110  private $registry;
111 
115  private $orderManagement;
116 
120  private $storeManager;
121 
125  protected function setUp()
126  {
127  parent::setUp();
128  $this->isProductSalableForRequestedQty = Bootstrap::getObjectManager()->get(
129  IsProductSalableForRequestedQtyInterface::class
130  );
131  $this->getProductSalableQty = Bootstrap::getObjectManager()->get(GetProductSalableQtyInterface::class);
132  $this->getStockItemConfiguration = Bootstrap::getObjectManager()->get(
133  GetStockItemConfigurationInterface::class
134  );
135  $this->saveStockItemConfiguration = Bootstrap::getObjectManager()->get(
136  SaveStockItemConfigurationInterface::class
137  );
138 
139  $this->searchCriteriaBuilder = Bootstrap::getObjectManager()->get(
140  SearchCriteriaBuilder::class
141  );
142 
143  $this->registry = Bootstrap::getObjectManager()->get(Registry::class);
144  $this->stockRepository = Bootstrap::getObjectManager()->get(StockRepositoryInterface::class);
145  $this->storeRepository = Bootstrap::getObjectManager()->get(StoreRepositoryInterface::class);
146  $this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
147  $this->cartManagement = Bootstrap::getObjectManager()->get(CartManagementInterface::class);
148  $this->cartRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class);
149  $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
150  $this->searchCriteriaBuilder = Bootstrap::getObjectManager()->get(SearchCriteriaBuilder::class);
151  $this->cartItemFactory = Bootstrap::getObjectManager()->get(CartItemInterfaceFactory::class);
152  $this->cleanupReservations = Bootstrap::getObjectManager()->get(CleanupReservationsInterface::class);
153  $this->orderRepository = Bootstrap::getObjectManager()->get(OrderRepositoryInterface::class);
154  $this->orderManagement = Bootstrap::getObjectManager()->get(OrderManagementInterface::class);
155  }
156 
171  {
172  $sku = 'SKU-1';
173  $stockId = 10;
174  //Initial amount of SKU-1 on StockId = 10 is 8.5
175  //Setting MinQty threshold as negative value we increase the Salable Quantity
176  //Salable Quantity: 8.5 - (-4.5) = 13
177  $quoteItemQty = 13;
178 
179  // Before backorder is set, Salable Quantity is 8.5
180  $this->assertEquals(8.5, $this->getProductSalableQty->execute($sku, $stockId));
181  $this->assertFalse($this->isProductSalableForRequestedQty->execute($sku, $stockId, 13)->isSalable());
182 
183  $stockItemConfiguration = $this->getStockItemConfiguration->execute($sku, $stockId);
184  $stockItemConfiguration->setUseConfigMinQty(false);
185  $stockItemConfiguration->setMinQty(-4.5);
186  $this->saveStockItemConfiguration->execute($sku, $stockId, $stockItemConfiguration);
187 
188  // Before backorder is set, Salable Quantity is 8.5
189  $this->assertEquals(8.5, $this->getProductSalableQty->execute($sku, $stockId));
190  $this->assertFalse($this->isProductSalableForRequestedQty->execute($sku, $stockId, 13)->isSalable());
191 
192  $stockItemConfiguration->setUseConfigBackorders(false);
193  $stockItemConfiguration->setBackorders(StockItemConfigurationInterface::BACKORDERS_YES_NONOTIFY);
194  $this->saveStockItemConfiguration->execute($sku, $stockId, $stockItemConfiguration);
195 
196  // After backorder is set, Salable Quantity is 8.5 - (-4.5) = 13
197  $this->assertEquals(13, $this->getProductSalableQty->execute($sku, $stockId));
198 
199  $this->assertTrue($this->isProductSalableForRequestedQty->execute($sku, $stockId, 13)->isSalable());
200  $this->assertFalse($this->isProductSalableForRequestedQty->execute($sku, $stockId, 14)->isSalable());
201 
202  $cart = $this->getCartByStockId($stockId);
203  $product = $this->productRepository->get($sku);
204  $cartItem = $this->getCartItem($product, $quoteItemQty, (int)$cart->getId());
205  $cart->addItem($cartItem);
206  $this->cartRepository->save($cart);
207 
208  $orderId = $this->cartManagement->placeOrder($cart->getId());
209  $this->assertFalse($this->isProductSalableForRequestedQty->execute($sku, $stockId, 1)->isSalable());
210  $this->deleteOrderById((int)$orderId);
211 
212  // Now the Salable Quantity of Product SKU-1 is infinite
213  $stockItemConfiguration->setMinQty(0);
214  $this->saveStockItemConfiguration->execute($sku, $stockId, $stockItemConfiguration);
215  $this->assertTrue($this->isProductSalableForRequestedQty->execute($sku, $stockId, 1)->isSalable());
216 
217  // Positive MinQty works the same as MinQty = 0 , so that Salable Quantity is infinite
218  $stockItemConfiguration->setMinQty(10);
219  $this->saveStockItemConfiguration->execute($sku, $stockId, $stockItemConfiguration);
220  $this->assertTrue($this->isProductSalableForRequestedQty->execute($sku, $stockId, 100)->isSalable());
221  }
222 
227  private function getCartByStockId(int $stockId): CartInterface
228  {
229  $searchCriteria = $this->searchCriteriaBuilder
230  ->addFilter('reserved_order_id', 'test_order_1')
231  ->create();
233  $cart = current($this->cartRepository->getList($searchCriteria)->getItems());
235  $stock = $this->stockRepository->get($stockId);
237  $salesChannels = $stock->getExtensionAttributes()->getSalesChannels();
238  $storeCode = 'store_for_';
239  foreach ($salesChannels as $salesChannel) {
240  if ($salesChannel->getType() == SalesChannelInterface::TYPE_WEBSITE) {
241  $storeCode .= $salesChannel->getCode();
242  break;
243  }
244  }
246  $store = $this->storeRepository->get($storeCode);
247  $this->storeManager->setCurrentStore($storeCode);
248  $cart->setStoreId($store->getId());
249 
250  return $cart;
251  }
252 
256  private function deleteOrderById(int $orderId)
257  {
258  $this->registry->unregister('isSecureArea');
259  $this->registry->register('isSecureArea', true);
260  $this->orderManagement->cancel($orderId);
261  $this->orderRepository->delete($this->orderRepository->get($orderId));
262  $this->registry->unregister('isSecureArea');
263  $this->registry->register('isSecureArea', false);
264  }
265 
272  private function getCartItem(ProductInterface $product, float $quoteItemQty, int $cartId): CartItemInterface
273  {
275  $cartItem =
276  $this->cartItemFactory->create(
277  [
278  'data' => [
280  CartItemInterface::KEY_QTY => $quoteItemQty,
282  'product_id' => $product->getId(),
283  'product' => $product
284  ]
285  ]
286  );
287  return $cartItem;
288  }
289 
290  protected function tearDown()
291  {
292  $this->cleanupReservations->execute();
293  }
294 }
$searchCriteria
$storeCode
Definition: indexer.php:15
$cartId
Definition: quote.php:22
$stock