Skip to content

Commit 081ff88

Browse files
committed
MC-40136: Create automated test for: "Update items stock status and low stock date after save config"
1 parent 960a51f commit 081ff88

File tree

4 files changed

+382
-1
lines changed

4 files changed

+382
-1
lines changed

dev/tests/integration/testsuite/Magento/Catalog/_files/out_of_stock_product_with_category.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
$product->setTypeId(Type::TYPE_SIMPLE)
2727
->setAttributeSetId($product->getDefaultAttributeSetId())
2828
->setWebsiteIds([1])
29-
->setName('Simple Product Out Of Stock')
29+
->setName('Simple Product Out Of Stock With Category')
3030
->setSku('out-of-stock-product')
3131
->setPrice(10)
3232
->setWeight(1)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Catalog\Helper\DefaultCategory;
10+
use Magento\Catalog\Model\Product\Attribute\Source\Status;
11+
use Magento\Catalog\Model\Product\Type;
12+
use Magento\Catalog\Model\Product\Visibility;
13+
use Magento\Catalog\Model\ProductFactory;
14+
use Magento\CatalogInventory\Model\Stock;
15+
use Magento\Store\Api\WebsiteRepositoryInterface;
16+
use Magento\TestFramework\Helper\Bootstrap;
17+
18+
$objectManager = Bootstrap::getObjectManager();
19+
/** @var ProductRepositoryInterface $productRepositoryFactory */
20+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
21+
/** @var ProductFactory $productFactory */
22+
$productFactory = $objectManager->get(ProductFactory::class);
23+
/** @var WebsiteRepositoryInterface $websiteRepository */
24+
$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class);
25+
/** @var DefaultCategory $defaultCategory */
26+
$defaultCategory = $objectManager->get(DefaultCategory::class);
27+
$defaultWebsiteId = $websiteRepository->get('base')->getId();
28+
$product = $productFactory->create();
29+
$product->setTypeId(Type::TYPE_SIMPLE)
30+
->setAttributeSetId($product->getDefaultAttributeSetId())
31+
->setWebsiteIds([$defaultWebsiteId])
32+
->setName('Simple Product Backorders No')
33+
->setSku('simple-backorders-no')
34+
->setPrice(20)
35+
->setWeight(10)
36+
->setShortDescription('Short description backorders no')
37+
->setDescription('Description with <b>html tag</b> backorders no')
38+
->setMetaTitle('meta title')
39+
->setMetaKeyword('meta keyword')
40+
->setMetaDescription('meta description')
41+
->setVisibility(Visibility::VISIBILITY_BOTH)
42+
->setStatus(Status::STATUS_ENABLED)
43+
->setCategoryIds([$defaultCategory->getId()])
44+
->setStockData([
45+
'use_config_manage_stock' => 1,
46+
'qty' => 20,
47+
'is_qty_decimal' => 0,
48+
'is_in_stock' => Stock::STOCK_IN_STOCK,
49+
'use_config_backorders' => 0,
50+
'backorders' => Stock::BACKORDERS_NO,
51+
]);
52+
$productRepository->save($product);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Catalog\Api\ProductRepositoryInterface;
9+
use Magento\Framework\Exception\NoSuchEntityException;
10+
use Magento\Framework\Registry;
11+
use Magento\TestFramework\Helper\Bootstrap;
12+
13+
$objectManager = Bootstrap::getObjectManager();
14+
/** @var Registry $registry */
15+
$registry = $objectManager->get(Registry::class);
16+
/** @var ProductRepositoryInterface $productRepository */
17+
$productRepository = $objectManager->get(ProductRepositoryInterface::class);
18+
$registry->unregister('isSecureArea');
19+
$registry->register('isSecureArea', true);
20+
21+
try {
22+
$productRepository->deleteById('simple-backorders-no');
23+
} catch (NoSuchEntityException $e) {
24+
// product already deleted
25+
}
26+
27+
$registry->unregister('isSecureArea');
28+
$registry->register('isSecureArea', false);
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogInventory\Model\ResourceModel\Stock;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Catalog\Model\Indexer\Product\Price\Processor as PriceProcessor;
12+
use Magento\CatalogInventory\Model\Configuration;
13+
use Magento\CatalogInventory\Model\Indexer\Stock\Processor as StockProcessor;
14+
use Magento\CatalogInventory\Model\Stock;
15+
use Magento\CatalogInventory\Model\StockRegistryStorage;
16+
use Magento\Framework\App\Config\MutableScopeConfigInterface;
17+
use Magento\Framework\Indexer\StateInterface;
18+
use Magento\Framework\ObjectManagerInterface;
19+
use Magento\Store\Model\ScopeInterface;
20+
use Magento\Store\Model\StoreManagerInterface;
21+
use Magento\TestFramework\Helper\Bootstrap;
22+
use PHPUnit\Framework\TestCase;
23+
24+
/**
25+
* Tests for stock item resource model
26+
*
27+
* @see \Magento\CatalogInventory\Model\ResourceModel\Stock\Item
28+
*/
29+
class ItemTest extends TestCase
30+
{
31+
/** @var ObjectManagerInterface */
32+
private $objectManager;
33+
34+
/** @var MutableScopeConfigInterface */
35+
private $mutableConfig;
36+
37+
/** @var Item */
38+
private $stockItemResource;
39+
40+
/** @var StoreManagerInterface */
41+
private $storeManager;
42+
43+
/** @var ProductRepositoryInterface */
44+
private $productRepository;
45+
46+
/** @var StockRegistryStorage */
47+
private $stockRegistryStorage;
48+
49+
/** @var StockProcessor */
50+
private $stockIndexerProcessor;
51+
52+
/** @var PriceProcessor */
53+
private $priceIndexerProcessor;
54+
55+
/**
56+
* @inheritdoc
57+
*/
58+
protected function setUp(): void
59+
{
60+
$this->objectManager = Bootstrap::getObjectManager();
61+
$this->mutableConfig = $this->objectManager->get(MutableScopeConfigInterface::class);
62+
$this->stockItemResource = $this->objectManager->get(Item::class);
63+
$this->storeManager = $this->objectManager->get(StoreManagerInterface::class);
64+
$this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
65+
$this->productRepository->cleanCache();
66+
$this->stockRegistryStorage = $this->objectManager->get(StockRegistryStorage::class);
67+
$this->stockIndexerProcessor = $this->objectManager->get(StockProcessor::class);
68+
$this->priceIndexerProcessor = $this->objectManager->get(PriceProcessor::class);
69+
}
70+
71+
/**
72+
* @dataProvider updateSetOutOfStockDataProvider
73+
* @magentoDataFixture Magento/Catalog/_files/product_simple_duplicated.php
74+
* @magentoDataFixture Magento/Catalog/_files/product_simple_backorders_no.php
75+
* @magentoConfigFixture default_store cataloginventory/item_options/min_qty 105
76+
* @magentoConfigFixture default_store cataloginventory/item_options/manage_stock 1
77+
* @param int $backorders
78+
* @param array $expectedStockItems
79+
* @magentoDbIsolation disabled
80+
* @return void
81+
*/
82+
public function testUpdateSetOutOfStock(int $backorders, array $expectedStockItems): void
83+
{
84+
$this->stockIndexerProcessor->reindexAll();
85+
$this->priceIndexerProcessor->reindexAll();
86+
$this->mutableConfig->setValue(Configuration::XML_PATH_BACKORDERS, $backorders, ScopeInterface::SCOPE_STORE);
87+
$websiteId = (int)$this->storeManager->getWebsite('admin')->getId();
88+
$this->stockItemResource->updateSetOutOfStock($websiteId);
89+
90+
$this->assertProductsStockItem($expectedStockItems);
91+
$this->assertEquals(StateInterface::STATUS_INVALID, $this->stockIndexerProcessor->getIndexer()->getStatus());
92+
$this->assertEquals(StateInterface::STATUS_INVALID, $this->priceIndexerProcessor->getIndexer()->getStatus());
93+
}
94+
95+
/**
96+
* @return array
97+
*/
98+
public function updateSetOutOfStockDataProvider(): array
99+
{
100+
return [
101+
'backorders_no' => [
102+
'backorders' => Stock::BACKORDERS_NO,
103+
'expected_stock_items' => [
104+
'simple-1' => [
105+
'is_in_stock' => Stock::STOCK_OUT_OF_STOCK,
106+
'stock_status_changed_auto' => 1,
107+
],
108+
'simple-backorders-no' => [
109+
'is_in_stock' => Stock::STOCK_OUT_OF_STOCK,
110+
'stock_status_changed_auto' => 1,
111+
],
112+
],
113+
],
114+
'backorders_yes' => [
115+
'backorders' => Stock::BACKORDERS_YES_NONOTIFY,
116+
'expected_stock_items' => [
117+
'simple-1' => [
118+
'is_in_stock' => Stock::STOCK_IN_STOCK,
119+
'stock_status_changed_auto' => 0,
120+
],
121+
'simple-backorders-no' => [
122+
'is_in_stock' => Stock::STOCK_OUT_OF_STOCK,
123+
'stock_status_changed_auto' => 1,
124+
],
125+
],
126+
],
127+
];
128+
}
129+
130+
/**
131+
* @dataProvider updateUpdateSetInStockDataProvider
132+
* @magentoDataFixture Magento/Catalog/_files/out_of_stock_product_with_category.php
133+
* @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php
134+
* @magentoConfigFixture default_store cataloginventory/item_options/min_qty 50
135+
* @param int $manageStock
136+
* @param array $expectedStockItems
137+
* @magentoDbIsolation disabled
138+
* @return void
139+
*/
140+
public function testUpdateSetInStock(int $manageStock, array $expectedStockItems): void
141+
{
142+
$this->updateProductsStockItem([
143+
'out-of-stock-product' => [
144+
'qty' => 60,
145+
'stock_status_changed_automatically_flag' => true,
146+
],
147+
'simple-out-of-stock' => [
148+
'use_config_manage_stock' => 0,
149+
'manage_stock' => 1,
150+
'qty' => 80,
151+
'stock_status_changed_automatically_flag' => true,
152+
],
153+
]);
154+
$this->stockIndexerProcessor->reindexAll();
155+
$this->priceIndexerProcessor->reindexAll();
156+
$this->mutableConfig->setValue(Configuration::XML_PATH_MANAGE_STOCK, $manageStock, ScopeInterface::SCOPE_STORE);
157+
$websiteId = (int)$this->storeManager->getWebsite('admin')->getId();
158+
$this->stockItemResource->updateSetInStock($websiteId);
159+
160+
$this->assertProductsStockItem($expectedStockItems);
161+
$this->assertEquals(StateInterface::STATUS_INVALID, $this->stockIndexerProcessor->getIndexer()->getStatus());
162+
$this->assertEquals(StateInterface::STATUS_INVALID, $this->priceIndexerProcessor->getIndexer()->getStatus());
163+
}
164+
165+
/**
166+
* @return array
167+
*/
168+
public function updateUpdateSetInStockDataProvider(): array
169+
{
170+
return [
171+
'manage_stock_yes' => [
172+
'manage_stock' => 1,
173+
'expected_stock_items' => [
174+
'out-of-stock-product' => [
175+
'is_in_stock' => Stock::STOCK_IN_STOCK,
176+
],
177+
'simple-out-of-stock' => [
178+
'is_in_stock' => Stock::STOCK_IN_STOCK,
179+
],
180+
],
181+
],
182+
'manage_stock_no' => [
183+
'manage_stock' => 0,
184+
'expected_stock_items' => [
185+
'out-of-stock-product' => [
186+
'is_in_stock' => Stock::STOCK_OUT_OF_STOCK,
187+
],
188+
'simple-out-of-stock' => [
189+
'is_in_stock' => Stock::STOCK_IN_STOCK,
190+
],
191+
],
192+
],
193+
];
194+
}
195+
196+
/**
197+
* @dataProvider updateLowStockDateDataProvider
198+
* @magentoDataFixture Magento/Catalog/_files/product_simple_with_url_key.php
199+
* @param int $manageStock
200+
* @param array $expectedLowStockDate
201+
* @return void
202+
*/
203+
public function testLowStockDate(int $manageStock, array $expectedLowStockDate): void
204+
{
205+
$this->updateProductsStockItem([
206+
'simple2' => [
207+
'use_config_manage_stock' => 0,
208+
'manage_stock' => 1,
209+
],
210+
]);
211+
$this->mutableConfig->setValue(Configuration::XML_PATH_MANAGE_STOCK, $manageStock, ScopeInterface::SCOPE_STORE);
212+
$this->mutableConfig->setValue(Configuration::XML_PATH_NOTIFY_STOCK_QTY, 105, ScopeInterface::SCOPE_STORE);
213+
$websiteId = (int)$this->storeManager->getWebsite('admin')->getId();
214+
$this->stockItemResource->updateLowStockDate($websiteId);
215+
216+
$this->assertLowStockDate($expectedLowStockDate);
217+
}
218+
219+
/**
220+
* @return array
221+
*/
222+
public function updateLowStockDateDataProvider(): array
223+
{
224+
return [
225+
'manage_stock_yes' => [
226+
'manage_stock' => 1,
227+
'expected_low_stock_date' => [
228+
'simple1' => [
229+
'is_low_stock_date_null' => false,
230+
],
231+
'simple2' => [
232+
'is_low_stock_date_null' => false,
233+
],
234+
],
235+
],
236+
'manage_stock_no' => [
237+
'manage_stock' => 0,
238+
'expected_low_stock_date' => [
239+
'simple1' => [
240+
'is_low_stock_date_null' => true,
241+
],
242+
'simple2' => [
243+
'is_low_stock_date_null' => false,
244+
],
245+
],
246+
],
247+
];
248+
}
249+
250+
/**
251+
* Update products stock item
252+
*
253+
* @param array $productsStockData
254+
* @return void
255+
*/
256+
private function updateProductsStockItem(array $productsStockData): void
257+
{
258+
foreach ($productsStockData as $sku => $stockData) {
259+
$product = $this->productRepository->get($sku, true, null, true);
260+
$stockItem = $product->getExtensionAttributes()->getStockItem();
261+
$stockItem->addData($stockData);
262+
$this->productRepository->save($product);
263+
}
264+
}
265+
266+
/**
267+
* Assert products stock item
268+
*
269+
* @param array $expectedStockItems
270+
* @return void
271+
*/
272+
private function assertProductsStockItem(array $expectedStockItems): void
273+
{
274+
$this->stockRegistryStorage->clean();
275+
foreach ($expectedStockItems as $sku => $expectedData) {
276+
$product = $this->productRepository->get($sku, false, null, true);
277+
$stockItem = $product->getExtensionAttributes()->getStockItem();
278+
$this->assertEmpty(array_diff_assoc($expectedData, $stockItem->getData()), 'Actual stock item data not equals expected data.');
279+
}
280+
}
281+
282+
/**
283+
* Assert low_stock_date value of products stock item
284+
*
285+
* @param array $expectedLowStockDate
286+
* @return void
287+
*/
288+
private function assertLowStockDate(array $expectedLowStockDate): void
289+
{
290+
$this->stockRegistryStorage->clean();
291+
foreach ($expectedLowStockDate as $sku => $expectedData) {
292+
$product = $this->productRepository->get($sku, false, null, true);
293+
$stockItem = $product->getExtensionAttributes()->getStockItem();
294+
if ($expectedData['is_low_stock_date_null']) {
295+
$this->assertNull($stockItem->getLowStockDate());
296+
} else {
297+
$this->assertNotNull($stockItem->getLowStockDate());
298+
}
299+
}
300+
}
301+
}

0 commit comments

Comments
 (0)