Skip to content

Commit 97a2027

Browse files
authored
Merge pull request #4809 from magento-tsg-csl3/2.3-develop-pr33
[TSG-CSL3] For 2.3 (pr33)
2 parents 296e280 + 5afdec0 commit 97a2027

File tree

16 files changed

+1061
-80
lines changed

16 files changed

+1061
-80
lines changed

app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/StockDataFilter.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
use Magento\CatalogInventory\Api\StockConfigurationInterface;
99
use Magento\Framework\App\Config\ScopeConfigInterface;
10+
use Magento\CatalogInventory\Model\Stock;
1011

1112
/**
1213
* Class StockDataFilter
@@ -60,8 +61,8 @@ public function filter(array $stockData)
6061
$stockData['qty'] = self::MAX_QTY_VALUE;
6162
}
6263

63-
if (isset($stockData['min_qty']) && (int)$stockData['min_qty'] < 0) {
64-
$stockData['min_qty'] = 0;
64+
if (isset($stockData['min_qty'])) {
65+
$stockData['min_qty'] = $this->purifyMinQty($stockData['min_qty'], $stockData['backorders']);
6566
}
6667

6768
if (!isset($stockData['is_decimal_divided']) || $stockData['is_qty_decimal'] == 0) {
@@ -70,4 +71,27 @@ public function filter(array $stockData)
7071

7172
return $stockData;
7273
}
74+
75+
/**
76+
* Purifies min_qty.
77+
*
78+
* @param int $minQty
79+
* @param int $backOrders
80+
* @return float
81+
*/
82+
private function purifyMinQty(int $minQty, int $backOrders): float
83+
{
84+
/**
85+
* As described in the documentation if the Backorders Option is disabled
86+
* it is recommended to set the Out Of Stock Threshold to a positive number.
87+
* That's why to clarify the logic to the end user the code below prevent him to set a negative number so such
88+
* a number will turn to zero.
89+
* @see https://docs.magento.com/m2/ce/user_guide/catalog/inventory-backorders.html
90+
*/
91+
if ($backOrders === Stock::BACKORDERS_NO && $minQty < 0) {
92+
$minQty = 0;
93+
}
94+
95+
return (float)$minQty;
96+
}
7397
}

app/code/Magento/Catalog/Model/Product/Option/Type/Date.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public function prepareForCart()
159159

160160
if ($this->_dateExists()) {
161161
if ($this->useCalendar()) {
162-
$timestamp += $this->_localeDate->date($value['date'], null, true, false)->getTimestamp();
162+
$timestamp += $this->_localeDate->date($value['date'], null, false, false)->getTimestamp();
163163
} else {
164164
$timestamp += mktime(0, 0, 0, $value['month'], $value['day'], $value['year']);
165165
}

app/code/Magento/Catalog/Test/Mftf/Test/AdminBackorderAllowedAddProductToCartTest.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@
2323
<createData entity="SimpleProductInStockQuantityZero" stepKey="createProduct"/>
2424

2525
<!-- Configure Magento to show out of stock products and to allow backorders -->
26-
<magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockEnable.path}} {{CatalogInventoryOptionsShowOutOfStockEnable.value}}" stepKey="setConfigShowOutOfStockTrue"/>
2726
<magentoCLI command="config:set {{CatalogInventoryItemOptionsBackordersEnable.path}} {{CatalogInventoryItemOptionsBackordersEnable.value}}" stepKey="setConfigAllowBackordersTrue"/>
2827
</before>
2928

3029
<after>
3130
<!-- Set Magento back to default configuration -->
32-
<magentoCLI command="config:set {{CatalogInventoryOptionsShowOutOfStockDisable.path}} {{CatalogInventoryOptionsShowOutOfStockDisable.value}}" stepKey="setConfigShowOutOfStockFalse"/>
3331
<magentoCLI command="config:set {{CatalogInventoryItemOptionsBackordersDisable.path}} {{CatalogInventoryItemOptionsBackordersDisable.value}}" stepKey="setConfigAllowBackordersFalse"/>
3432
<deleteData createDataKey="createProduct" stepKey="deleteProduct"/>
3533
</after>

app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/StockDataFilterTest.php

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@
66
namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Initialization;
77

88
use Magento\Catalog\Controller\Adminhtml\Product\Initialization\StockDataFilter;
9+
use Magento\CatalogInventory\Model\Stock;
10+
use Magento\Framework\App\Config\ScopeConfigInterface;
11+
use Magento\CatalogInventory\Model\Configuration;
12+
use PHPUnit\Framework\TestCase;
913

1014
/**
11-
* Class StockDataFilterTest
15+
* StockDataFilter test.
1216
*/
13-
class StockDataFilterTest extends \PHPUnit\Framework\TestCase
17+
class StockDataFilterTest extends TestCase
1418
{
1519
/**
1620
* @var \PHPUnit_Framework_MockObject_MockObject
@@ -27,35 +31,43 @@ class StockDataFilterTest extends \PHPUnit\Framework\TestCase
2731
*/
2832
protected $stockDataFilter;
2933

30-
/** @var \PHPUnit_Framework_MockObject_MockObject */
34+
/**
35+
* @var \PHPUnit_Framework_MockObject_MockObject
36+
*/
3137
protected $stockConfiguration;
3238

39+
/**
40+
* @inheritdoc
41+
*/
3342
protected function setUp()
3443
{
35-
$this->scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
44+
$this->scopeConfigMock = $this->createMock(ScopeConfigInterface::class);
3645

37-
$this->scopeConfigMock->expects($this->any())->method('getValue')->will($this->returnValue(1));
46+
$this->scopeConfigMock->method('getValue')
47+
->will($this->returnValue(1));
3848

3949
$this->stockConfiguration = $this->createPartialMock(
40-
\Magento\CatalogInventory\Model\Configuration::class,
50+
Configuration::class,
4151
['getManageStock']
4252
);
4353

4454
$this->stockDataFilter = new StockDataFilter($this->scopeConfigMock, $this->stockConfiguration);
4555
}
4656

4757
/**
58+
* Tests filter method.
59+
*
4860
* @param array $inputStockData
4961
* @param array $outputStockData
62+
* @return void
5063
*
5164
* @covers \Magento\Catalog\Controller\Adminhtml\Product\Initialization\StockDataFilter::filter
5265
* @dataProvider filterDataProvider
5366
*/
5467
public function testFilter(array $inputStockData, array $outputStockData)
5568
{
5669
if (isset($inputStockData['use_config_manage_stock']) && $inputStockData['use_config_manage_stock'] === 1) {
57-
$this->stockConfiguration->expects($this->once())
58-
->method('getManageStock')
70+
$this->stockConfiguration->method('getManageStock')
5971
->will($this->returnValue($outputStockData['manage_stock']));
6072
}
6173

@@ -93,8 +105,13 @@ public function filterDataProvider()
93105
],
94106
],
95107
'case4' => [
96-
'inputStockData' => ['min_qty' => -1],
97-
'outputStockData' => ['min_qty' => 0, 'is_decimal_divided' => 0, 'use_config_manage_stock' => 0],
108+
'inputStockData' => ['min_qty' => -1, 'backorders' => Stock::BACKORDERS_NO],
109+
'outputStockData' => [
110+
'min_qty' => 0,
111+
'is_decimal_divided' => 0,
112+
'use_config_manage_stock' => 0,
113+
'backorders' => Stock::BACKORDERS_NO,
114+
],
98115
],
99116
'case5' => [
100117
'inputStockData' => ['is_qty_decimal' => 0],
@@ -103,7 +120,25 @@ public function filterDataProvider()
103120
'is_decimal_divided' => 0,
104121
'use_config_manage_stock' => 0,
105122
],
106-
]
123+
],
124+
'case6' => [
125+
'inputStockData' => ['min_qty' => -1, 'backorders' => Stock::BACKORDERS_YES_NONOTIFY],
126+
'outputStockData' => [
127+
'min_qty' => -1,
128+
'is_decimal_divided' => 0,
129+
'use_config_manage_stock' => 0,
130+
'backorders' => Stock::BACKORDERS_YES_NONOTIFY,
131+
],
132+
],
133+
'case7' => [
134+
'inputStockData' => ['min_qty' => -1, 'backorders' => Stock::BACKORDERS_YES_NOTIFY],
135+
'outputStockData' => [
136+
'min_qty' => -1,
137+
'is_decimal_divided' => 0,
138+
'use_config_manage_stock' => 0,
139+
'backorders' => Stock::BACKORDERS_YES_NOTIFY,
140+
],
141+
],
107142
];
108143
}
109144
}

app/code/Magento/CatalogInventory/Model/ResourceModel/Stock/Item.php

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Magento\Framework\DB\Select;
1515
use Magento\Framework\App\ObjectManager;
1616
use Magento\Framework\Stdlib\DateTime\DateTime;
17+
use Zend_Db_Expr;
1718

1819
/**
1920
* Stock item resource model
@@ -183,16 +184,12 @@ public function updateSetOutOfStock(int $websiteId)
183184
'is_in_stock = ' . Stock::STOCK_IN_STOCK,
184185
'(use_config_manage_stock = 1 AND 1 = ' . $this->stockConfiguration->getManageStock() . ')'
185186
. ' OR (use_config_manage_stock = 0 AND manage_stock = 1)',
186-
'(use_config_min_qty = 1 AND qty <= ' . $this->stockConfiguration->getMinQty() . ')'
187-
. ' OR (use_config_min_qty = 0 AND qty <= min_qty)',
187+
'(' . $this->getBackordersExpr() .' = 0 AND qty <= ' . $this->getMinQtyExpr() . ')'
188+
. ' OR (' . $this->getBackordersExpr() .' != 0 AND '
189+
. $this->getMinQtyExpr() . ' != 0 AND qty <= ' . $this->getMinQtyExpr() . ')',
188190
'product_id IN (' . $select->assemble() . ')',
189191
];
190-
$backordersWhere = '(use_config_backorders = 0 AND backorders = ' . Stock::BACKORDERS_NO . ')';
191-
if (Stock::BACKORDERS_NO == $this->stockConfiguration->getBackorders()) {
192-
$where[] = $backordersWhere . ' OR use_config_backorders = 1';
193-
} else {
194-
$where[] = $backordersWhere;
195-
}
192+
196193
$connection->update($this->getMainTable(), $values, $where);
197194

198195
$this->stockIndexerProcessor->markIndexerAsInvalid();
@@ -215,8 +212,8 @@ public function updateSetInStock(int $websiteId)
215212
$where = [
216213
'website_id = ' . $websiteId,
217214
'stock_status_changed_auto = 1',
218-
'(use_config_min_qty = 1 AND qty > ' . $this->stockConfiguration->getMinQty() . ')'
219-
. ' OR (use_config_min_qty = 0 AND qty > min_qty)',
215+
'(qty > ' . $this->getMinQtyExpr() . ')'
216+
. ' OR (' . $this->getBackordersExpr() . ' != 0 AND ' . $this->getMinQtyExpr() . ' = 0)', // If infinite
220217
'product_id IN (' . $select->assemble() . ')',
221218
];
222219
$manageStockWhere = '(use_config_manage_stock = 0 AND manage_stock = 1)';
@@ -304,12 +301,12 @@ public function getBackordersExpr(string $tableAlias = ''): \Zend_Db_Expr
304301
}
305302

306303
/**
307-
* Get Minimum Sale Quantity Expression
304+
* Get Minimum Sale Quantity Expression.
308305
*
309306
* @param string $tableAlias
310-
* @return \Zend_Db_Expr
307+
* @return Zend_Db_Expr
311308
*/
312-
public function getMinSaleQtyExpr(string $tableAlias = ''): \Zend_Db_Expr
309+
public function getMinSaleQtyExpr(string $tableAlias = ''): Zend_Db_Expr
313310
{
314311
if ($tableAlias) {
315312
$tableAlias .= '.';
@@ -323,6 +320,26 @@ public function getMinSaleQtyExpr(string $tableAlias = ''): \Zend_Db_Expr
323320
return $itemMinSaleQty;
324321
}
325322

323+
/**
324+
* Get Min Qty Expression
325+
*
326+
* @param string $tableAlias
327+
* @return Zend_Db_Expr
328+
*/
329+
public function getMinQtyExpr(string $tableAlias = ''): Zend_Db_Expr
330+
{
331+
if ($tableAlias) {
332+
$tableAlias .= '.';
333+
}
334+
$itemBackorders = $this->getConnection()->getCheckSql(
335+
$tableAlias . 'use_config_min_qty = 1',
336+
$this->stockConfiguration->getMinQty(),
337+
$tableAlias . 'min_qty'
338+
);
339+
340+
return $itemBackorders;
341+
}
342+
326343
/**
327344
* Build select for products with types from config
328345
*

app/code/Magento/CatalogInventory/Model/StockStateProvider.php

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,31 @@ public function __construct(
7272
*/
7373
public function verifyStock(StockItemInterface $stockItem)
7474
{
75+
// Manage stock, but qty is null
7576
if ($stockItem->getQty() === null && $stockItem->getManageStock()) {
7677
return false;
7778
}
79+
80+
// Backorders are not allowed and qty reached min qty
7881
if ($stockItem->getBackorders() == StockItemInterface::BACKORDERS_NO
7982
&& $stockItem->getQty() <= $stockItem->getMinQty()
8083
) {
8184
return false;
8285
}
86+
87+
$backordersAllowed = [Stock::BACKORDERS_YES_NONOTIFY, Stock::BACKORDERS_YES_NOTIFY];
88+
if (in_array($stockItem->getBackorders(), $backordersAllowed)) {
89+
// Infinite - let it be In stock
90+
if ($stockItem->getMinQty() == 0) {
91+
return true;
92+
}
93+
94+
// qty reached min qty - let it stand Out Of Stock
95+
if ($stockItem->getQty() <= $stockItem->getMinQty()) {
96+
return false;
97+
}
98+
}
99+
83100
return true;
84101
}
85102

@@ -245,15 +262,17 @@ public function checkQty(StockItemInterface $stockItem, $qty)
245262
if (!$stockItem->getManageStock()) {
246263
return true;
247264
}
265+
266+
$backordersAllowed = [Stock::BACKORDERS_YES_NONOTIFY, Stock::BACKORDERS_YES_NOTIFY];
267+
// Infinite check
268+
if ($stockItem->getMinQty() == 0 && in_array($stockItem->getBackorders(), $backordersAllowed)) {
269+
return true;
270+
}
271+
248272
if ($stockItem->getQty() - $stockItem->getMinQty() - $qty < 0) {
249-
switch ($stockItem->getBackorders()) {
250-
case \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NONOTIFY:
251-
case \Magento\CatalogInventory\Model\Stock::BACKORDERS_YES_NOTIFY:
252-
break;
253-
default:
254-
return false;
255-
}
273+
return false;
256274
}
275+
257276
return true;
258277
}
259278

app/code/Magento/CatalogInventory/Model/System/Config/Backend/Minqty.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,36 @@
66

77
namespace Magento\CatalogInventory\Model\System\Config\Backend;
88

9+
use Magento\CatalogInventory\Model\Stock;
10+
911
/**
10-
* Minimum product qty backend model
12+
* Minimum product qty backend model.
1113
*/
1214
class Minqty extends \Magento\Framework\App\Config\Value
1315
{
1416
/**
15-
* Validate minimum product qty value
17+
* Validate minimum product qty value.
1618
*
1719
* @return $this
1820
*/
1921
public function beforeSave()
2022
{
2123
parent::beforeSave();
22-
$minQty = (int) $this->getValue() >= 0 ? (int) $this->getValue() : (int) $this->getOldValue();
24+
$minQty = (float)$this->getValue();
25+
26+
/**
27+
* As described in the documentation if the Backorders Option is disabled
28+
* it is recommended to set the Out Of Stock Threshold to a positive number.
29+
* That's why to clarify the logic to the end user the code below prevent him to set a negative number so such
30+
* a number will turn to zero.
31+
* @see https://docs.magento.com/m2/ce/user_guide/catalog/inventory-backorders.html
32+
*/
33+
if ($this->getFieldsetDataValue("backorders") == Stock::BACKORDERS_NO && $minQty < 0) {
34+
$minQty = 0;
35+
}
36+
2337
$this->setValue((string) $minQty);
38+
2439
return $this;
2540
}
2641
}

0 commit comments

Comments
 (0)