Skip to content

Commit 25b568d

Browse files
committed
Merge remote-tracking branch 'origin/MC-40136' into 2.4-develop-sidecar-pr11
2 parents 4520d2d + 1ca4742 commit 25b568d

File tree

4 files changed

+385
-1
lines changed

4 files changed

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

0 commit comments

Comments
 (0)