Skip to content

Commit 515b0b8

Browse files
authored
Merge pull request #1164 from magento-dragons/MAGETWO-62271
Fixed issues: - MAGETWO-64249 Issue with integration test Magento/Setup/Console/Command/I18nCollectPhrasesCommandTest.php on Travis CI - MAGETWO-62271 Inconsistent saving of Stock Data
2 parents f5c8add + 7c29f6f commit 515b0b8

31 files changed

+1834
-650
lines changed

app/code/Magento/Catalog/Model/Product.php

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,13 +2509,15 @@ public function setTypeId($typeId)
25092509
/**
25102510
* {@inheritdoc}
25112511
*
2512-
* @return \Magento\Catalog\Api\Data\ProductExtensionInterface|null
2512+
* @return \Magento\Catalog\Api\Data\ProductExtensionInterface
25132513
*/
25142514
public function getExtensionAttributes()
25152515
{
25162516
$extensionAttributes = $this->_getExtensionAttributes();
2517-
if (!$extensionAttributes) {
2518-
return $this->extensionAttributesFactory->create(\Magento\Catalog\Api\Data\ProductInterface::class);
2517+
if (null === $extensionAttributes) {
2518+
/** @var \Magento\Catalog\Api\Data\ProductExtensionInterface $extensionAttributes */
2519+
$extensionAttributes = $this->extensionAttributesFactory->create(ProductInterface::class);
2520+
$this->setExtensionAttributes($extensionAttributes);
25192521
}
25202522
return $extensionAttributes;
25212523
}
@@ -2639,4 +2641,68 @@ public function setAssociatedProductIds(array $productIds)
26392641
$this->getExtensionAttributes()->setConfigurableProductLinks($productIds);
26402642
return $this;
26412643
}
2644+
2645+
/**
2646+
* Get quantity and stock status data
2647+
*
2648+
* @return array|null
2649+
*
2650+
* @deprecated as Product model shouldn't be responsible for stock status
2651+
* @see StockItemInterface when you want to change the stock data
2652+
* @see StockStatusInterface when you want to read the stock data for representation layer (storefront)
2653+
* @see StockItemRepositoryInterface::save as extension point for customization of saving process
2654+
*/
2655+
public function getQuantityAndStockStatus()
2656+
{
2657+
return $this->getData('quantity_and_stock_status');
2658+
}
2659+
2660+
/**
2661+
* Set quantity and stock status data
2662+
*
2663+
* @param array $quantityAndStockStatusData
2664+
* @return $this
2665+
*
2666+
* @deprecated as Product model shouldn't be responsible for stock status
2667+
* @see StockItemInterface when you want to change the stock data
2668+
* @see StockStatusInterface when you want to read the stock data for representation layer (storefront)
2669+
* @see StockItemRepositoryInterface::save as extension point for customization of saving process
2670+
*/
2671+
public function setQuantityAndStockStatus($quantityAndStockStatusData)
2672+
{
2673+
$this->setData('quantity_and_stock_status', $quantityAndStockStatusData);
2674+
return $this;
2675+
}
2676+
2677+
/**
2678+
* Get stock data
2679+
*
2680+
* @return array|null
2681+
*
2682+
* @deprecated as Product model shouldn't be responsible for stock status
2683+
* @see StockItemInterface when you want to change the stock data
2684+
* @see StockStatusInterface when you want to read the stock data for representation layer (storefront)
2685+
* @see StockItemRepositoryInterface::save as extension point for customization of saving process
2686+
*/
2687+
public function getStockData()
2688+
{
2689+
return $this->getData('stock_data');
2690+
}
2691+
2692+
/**
2693+
* Set stock data
2694+
*
2695+
* @param array $stockData
2696+
* @return $this
2697+
*
2698+
* @deprecated as Product model shouldn't be responsible for stock status
2699+
* @see StockItemInterface when you want to change the stock data
2700+
* @see StockStatusInterface when you want to read the stock data for representation layer (storefront)
2701+
* @see StockItemRepositoryInterface::save as extension point for customization of saving process
2702+
*/
2703+
public function setStockData($stockData)
2704+
{
2705+
$this->setData('stock_data', $stockData);
2706+
return $this;
2707+
}
26422708
}

app/code/Magento/Catalog/Model/Product/Attribute/Backend/Stock.php

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6-
76
namespace Magento\Catalog\Model\Product\Attribute\Backend;
87

98
use Magento\Catalog\Model\Product;
109

1110
/**
1211
* Quantity and Stock Status attribute processing
12+
*
13+
* @deprecated as this attribute should be removed
14+
* @see StockItemInterface when you want to change the stock data
15+
* @see StockStatusInterface when you want to read the stock data for representation layer (storefront)
16+
* @see StockItemRepositoryInterface::save as extension point for customization of saving process
1317
*/
1418
class Stock extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
1519
{
@@ -47,25 +51,6 @@ public function afterLoad($object)
4751
return parent::afterLoad($object);
4852
}
4953

50-
/**
51-
* Prepare inventory data from custom attribute
52-
*
53-
* @param Product $object
54-
* @return void
55-
*/
56-
public function beforeSave($object)
57-
{
58-
$stockData = $object->getData($this->getAttribute()->getAttributeCode());
59-
if (isset($stockData['qty']) && $stockData['qty'] === '') {
60-
$stockData['qty'] = null;
61-
}
62-
if ($object->getStockData() !== null && $stockData !== null) {
63-
$object->setStockData(array_replace((array)$object->getStockData(), (array)$stockData));
64-
}
65-
$object->unsetData($this->getAttribute()->getAttributeCode());
66-
parent::beforeSave($object);
67-
}
68-
6954
/**
7055
* Validate
7156
*

app/code/Magento/Catalog/Model/Product/Copier.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ public function copy(\Magento\Catalog\Model\Product $product)
5959

6060
/** @var \Magento\Catalog\Model\Product $duplicate */
6161
$duplicate = $this->productFactory->create();
62-
$duplicate->setData($product->getData());
62+
$productData = $product->getData();
63+
$productData = $this->removeStockItem($productData);
64+
$duplicate->setData($productData);
6365
$duplicate->setOptions([]);
6466
$duplicate->setIsDuplicate(true);
6567
$duplicate->setOriginalLinkId($product->getData($metadata->getLinkField()));
@@ -116,4 +118,21 @@ private function getMetadataPool()
116118
}
117119
return $this->metadataPool;
118120
}
121+
122+
/**
123+
* Remove stock item
124+
*
125+
* @param array $productData
126+
* @return array
127+
*/
128+
private function removeStockItem(array $productData)
129+
{
130+
if (isset($productData[ProductInterface::EXTENSION_ATTRIBUTES_KEY])) {
131+
$extensionAttributes = $productData[ProductInterface::EXTENSION_ATTRIBUTES_KEY];
132+
if (null !== $extensionAttributes->getStockItem()) {
133+
$extensionAttributes->setData('stock_item', null);
134+
}
135+
}
136+
return $productData;
137+
}
119138
}

app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Backend/StockTest.php

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -74,68 +74,4 @@ public function testAfterLoad()
7474
$this->assertEquals(1, $data[self::ATTRIBUTE_NAME]['is_in_stock']);
7575
$this->assertEquals(5, $data[self::ATTRIBUTE_NAME]['qty']);
7676
}
77-
78-
public function testBeforeSave()
79-
{
80-
$object = new \Magento\Framework\DataObject(
81-
[
82-
self::ATTRIBUTE_NAME => ['is_in_stock' => 1, 'qty' => 5],
83-
'stock_data' => ['is_in_stock' => 2, 'qty' => 2],
84-
]
85-
);
86-
$stockData = $object->getStockData();
87-
$this->assertEquals(2, $stockData['is_in_stock']);
88-
$this->assertEquals(2, $stockData['qty']);
89-
$this->assertNotEmpty($object->getData(self::ATTRIBUTE_NAME));
90-
91-
$this->model->beforeSave($object);
92-
93-
$stockData = $object->getStockData();
94-
$this->assertEquals(1, $stockData['is_in_stock']);
95-
$this->assertEquals(5, $stockData['qty']);
96-
$this->assertNull($object->getData(self::ATTRIBUTE_NAME));
97-
}
98-
99-
public function testBeforeSaveQtyIsEmpty()
100-
{
101-
$object = new \Magento\Framework\DataObject(
102-
[
103-
self::ATTRIBUTE_NAME => ['is_in_stock' => 1, 'qty' => ''],
104-
'stock_data' => ['is_in_stock' => 2, 'qty' => ''],
105-
]
106-
);
107-
108-
$this->model->beforeSave($object);
109-
110-
$stockData = $object->getStockData();
111-
$this->assertNull($stockData['qty']);
112-
}
113-
114-
public function testBeforeSaveQtyIsZero()
115-
{
116-
$object = new \Magento\Framework\DataObject(
117-
[
118-
self::ATTRIBUTE_NAME => ['is_in_stock' => 1, 'qty' => 0],
119-
'stock_data' => ['is_in_stock' => 2, 'qty' => 0],
120-
]
121-
);
122-
123-
$this->model->beforeSave($object);
124-
125-
$stockData = $object->getStockData();
126-
$this->assertEquals(0, $stockData['qty']);
127-
}
128-
129-
public function testBeforeSaveNoStockData()
130-
{
131-
$object = new \Magento\Framework\DataObject(
132-
[
133-
self::ATTRIBUTE_NAME => ['is_in_stock' => 1, 'qty' => 0]
134-
]
135-
);
136-
137-
$this->model->beforeSave($object);
138-
$this->assertNull($object->getStockData());
139-
$this->assertNull($object->getData(self::ATTRIBUTE_NAME));
140-
}
14177
}

app/code/Magento/Catalog/Test/Unit/Model/Product/CopierTest.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
*/
66
namespace Magento\Catalog\Test\Unit\Model\Product;
77

8+
use Magento\Catalog\Api\Data\ProductInterface;
89
use \Magento\Catalog\Model\Product\Copier;
910

11+
/**
12+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
13+
*/
1014
class CopierTest extends \PHPUnit_Framework_TestCase
1115
{
1216
/**
@@ -80,10 +84,28 @@ protected function setUp()
8084

8185
public function testCopy()
8286
{
87+
$stockItem = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockItemInterface::class)
88+
->getMock();
89+
$extensionAttributes = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductExtension::class)
90+
->setMethods(['getStockItem', 'setData'])
91+
->getMock();
92+
$extensionAttributes
93+
->expects($this->once())
94+
->method('getStockItem')
95+
->willReturn($stockItem);
96+
$extensionAttributes
97+
->expects($this->once())
98+
->method('setData')
99+
->with('stock_item', null);
100+
101+
$productData = [
102+
'product data' => ['product data'],
103+
ProductInterface::EXTENSION_ATTRIBUTES_KEY => $extensionAttributes,
104+
];
83105
$this->productMock->expects($this->atLeastOnce())->method('getWebsiteIds');
84106
$this->productMock->expects($this->atLeastOnce())->method('getCategoryIds');
85107
$this->productMock->expects($this->any())->method('getData')->willReturnMap([
86-
['', null, 'product data'],
108+
['', null, $productData],
87109
['linkField', null, '1'],
88110
]);
89111

@@ -135,7 +157,7 @@ public function testCopy()
135157
)->with(
136158
\Magento\Store\Model\Store::DEFAULT_STORE_ID
137159
);
138-
$duplicateMock->expects($this->once())->method('setData')->with('product data');
160+
$duplicateMock->expects($this->once())->method('setData')->with($productData);
139161
$this->copyConstructorMock->expects($this->once())->method('build')->with($this->productMock, $duplicateMock);
140162
$duplicateMock->expects($this->once())->method('getUrlKey')->willReturn('urk-key-1');
141163
$duplicateMock->expects($this->once())->method('setUrlKey')->with('urk-key-2');

app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,11 @@ class ProductTest extends \PHPUnit_Framework_TestCase
195195
*/
196196
private $collectionFactoryMock;
197197

198+
/**
199+
* @var ProductExtensionInterface|\PHPUnit_Framework_MockObject_MockObject
200+
*/
201+
private $extensionAttributes;
202+
198203
/**
199204
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
200205
*/
@@ -392,8 +397,16 @@ protected function setUp()
392397
->setMethods(['create'])
393398
->getMock();
394399
$this->mediaConfig = $this->getMock(\Magento\Catalog\Model\Product\Media\Config::class, [], [], '', false);
395-
$this->objectManagerHelper = new ObjectManagerHelper($this);
396400

401+
$this->extensionAttributes = $this->getMockBuilder(ProductExtensionInterface::class)
402+
->setMethods(['getStockItem'])
403+
->getMock();
404+
$this->extensionAttributesFactory
405+
->expects($this->any())
406+
->method('create')
407+
->willReturn($this->extensionAttributes);
408+
409+
$this->objectManagerHelper = new ObjectManagerHelper($this);
397410
$this->model = $this->objectManagerHelper->getObject(
398411
\Magento\Catalog\Model\Product::class,
399412
[

app/code/Magento/CatalogInventory/Model/Plugin/AfterProductLoad.php

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,28 @@
44
* Copyright © Magento, Inc. All rights reserved.
55
* See COPYING.txt for license details.
66
*/
7-
87
namespace Magento\CatalogInventory\Model\Plugin;
98

9+
/**
10+
* @deprecated Stock Item as a part of ExtensionAttributes is deprecated
11+
* @see StockItemInterface when you want to change the stock data
12+
* @see StockStatusInterface when you want to read the stock data for representation layer (storefront)
13+
* @see StockItemRepositoryInterface::save as extension point for customization of saving process
14+
*/
1015
class AfterProductLoad
1116
{
1217
/**
1318
* @var \Magento\CatalogInventory\Api\StockRegistryInterface
1419
*/
15-
protected $stockRegistry;
16-
17-
/**
18-
* @var \Magento\Catalog\Api\Data\ProductExtensionFactory
19-
*/
20-
protected $productExtensionFactory;
20+
private $stockRegistry;
2121

2222
/**
2323
* @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
24-
* @param \Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory
2524
*/
2625
public function __construct(
27-
\Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
28-
\Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory
26+
\Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
2927
) {
3028
$this->stockRegistry = $stockRegistry;
31-
$this->productExtensionFactory = $productExtensionFactory;
3229
}
3330

3431
/**
@@ -40,10 +37,6 @@ public function __construct(
4037
public function afterLoad(\Magento\Catalog\Model\Product $product)
4138
{
4239
$productExtension = $product->getExtensionAttributes();
43-
if ($productExtension === null) {
44-
$productExtension = $this->productExtensionFactory->create();
45-
}
46-
// stockItem := \Magento\CatalogInventory\Api\Data\StockItemInterface
4740
$productExtension->setStockItem($this->stockRegistry->getStockItem($product->getId()));
4841
$product->setExtensionAttributes($productExtension);
4942
return $product;

0 commit comments

Comments
 (0)