Skip to content

Commit 8af9827

Browse files
committed
MAGETWO-83706: Scheduled Update to existing Group Price / Special Price removes the previously configured price, or results in changes not being saved
1 parent 5c3f81e commit 8af9827

File tree

6 files changed

+338
-150
lines changed

6 files changed

+338
-150
lines changed

app/code/Magento/Catalog/Model/Product/TierPrice/SaveHandler.php renamed to app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/SaveHandler.php

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

88
use Magento\Framework\EntityManager\Operation\ExtensionInterface;
99
use Magento\Store\Model\StoreManagerInterface;
@@ -78,23 +78,28 @@ public function execute($entity, $arguments = [])
7878
$attribute = $this->attributeRepository->get('tier_price');
7979
$priceRows = $entity->getData($attribute->getName());
8080
if (null !== $priceRows) {
81+
if (!is_array($priceRows)) {
82+
throw new \Magento\Framework\Exception\LocalizedException(
83+
__('Something went wrong while processing the request.')
84+
);
85+
}
8186
$websiteId = $this->storeManager->getStore($entity->getStoreId())->getWebsiteId();
8287
$isGlobal = $attribute->isScopeGlobal() || $websiteId === 0;
8388
$identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField();
84-
$priceRows = array_filter((array)$priceRows);
89+
$priceRows = array_filter($priceRows);
8590
$productId = $entity->getData($identifierField);
8691

8792
// prepare and save data
8893
foreach ($priceRows as $data) {
8994
$isPriceWebsiteGlobal = (int)$data['website_id'] === 0;
90-
if (($isGlobal === $isPriceWebsiteGlobal)
95+
if ($isGlobal === $isPriceWebsiteGlobal
9196
|| !empty($data['price_qty'])
9297
|| isset($data['cust_group'])
9398
) {
9499
$tierPrice = $this->prepareTierPrice($data);
95100
$price = new \Magento\Framework\DataObject($tierPrice);
96101
$price->setData(
97-
$this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField(),
102+
$identifierField,
98103
$productId
99104
);
100105
$this->tierPriceResource->savePriceData($price);
@@ -130,21 +135,21 @@ private function getAdditionalFields(array $objectArray): array
130135
private function getPercentage(array $priceRow)
131136
{
132137
return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value'])
133-
? $priceRow['percentage_value']
138+
? (int)$priceRow['percentage_value']
134139
: null;
135140
}
136141

137142
/**
138143
* Prepare tier price data by provided price row data
139144
*
140-
* @param $data
145+
* @param array $data
141146
* @return array
142147
* @throws \Magento\Framework\Exception\LocalizedException
143148
*/
144149
private function prepareTierPrice(array $data): array
145150
{
146151
$useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId();
147-
$customerGroupId = !$useForAllGroups ? $data['cust_group'] : 0;
152+
$customerGroupId = $useForAllGroups ? 0 : $data['cust_group'];
148153
$tierPrice = array_merge(
149154
$this->getAdditionalFields($data),
150155
[

app/code/Magento/Catalog/Model/Product/TierPrice/UpdateHandler.php renamed to app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php

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

88
use Magento\Framework\EntityManager\Operation\ExtensionInterface;
99
use Magento\Catalog\Api\Data\ProductInterface;
@@ -43,7 +43,6 @@ class UpdateHandler implements ExtensionInterface
4343
*/
4444
private $tierPriceResource;
4545

46-
4746
/**
4847
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
4948
* @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
@@ -77,10 +76,15 @@ public function execute($entity, $arguments = [])
7776
$attribute = $this->attributeRepository->get('tier_price');
7877
$priceRows = $entity->getData($attribute->getName());
7978
if (null !== $priceRows) {
79+
if (!is_array($priceRows)) {
80+
throw new \Magento\Framework\Exception\LocalizedException(
81+
__('Something went wrong while processing the request.')
82+
);
83+
}
8084
$websiteId = $this->storeManager->getStore($entity->getStoreId())->getWebsiteId();
8185
$isGlobal = $attribute->isScopeGlobal() || $websiteId === 0;
8286
$identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField();
83-
$priceRows = array_filter((array)$priceRows);
87+
$priceRows = array_filter($priceRows);
8488
$productId = $entity->getData($identifierField);
8589
$old = [];
8690
$new = [];
@@ -89,7 +93,7 @@ public function execute($entity, $arguments = [])
8993
$origPrices = $entity->getOrigData($attribute->getName());
9094
if (is_array($origPrices)) {
9195
foreach ($origPrices as $data) {
92-
if ($isGlobal === $this->isWebsiteGlobal($data['website_id'])) {
96+
if ($isGlobal === $this->isWebsiteGlobal((int)$data['website_id'])) {
9397
$key = $this->getPriceKey($data);
9498
$old[$key] = $data;
9599
}
@@ -99,9 +103,9 @@ public function execute($entity, $arguments = [])
99103
// prepare data for save
100104
foreach ($priceRows as $data) {
101105
if (empty($data['delete'])
102-
|| !empty($data['price_qty'])
103-
|| isset($data['cust_group'])
104-
|| ($isGlobal === $this->isWebsiteGlobal($data['website_id']))
106+
&& (!empty($data['price_qty'])
107+
|| isset($data['cust_group'])
108+
|| $isGlobal === $this->isWebsiteGlobal((int)$data['website_id']))
105109
) {
106110
$key = $this->getPriceKey($data);
107111
$new[$key] = $this->prepareTierPrice($data);
@@ -136,7 +140,7 @@ private function getAdditionalFields(array $objectArray): array
136140
$percentageValue = $this->getPercentage($objectArray);
137141
return [
138142
'value' => $percentageValue ? null : $objectArray['price'],
139-
'percentage_value' => $percentageValue ?: null
143+
'percentage_value' => $percentageValue ?: null,
140144
];
141145
}
142146

@@ -149,7 +153,7 @@ private function getAdditionalFields(array $objectArray): array
149153
private function getPercentage(array $priceRow)
150154
{
151155
return isset($priceRow['percentage_value']) && is_numeric($priceRow['percentage_value'])
152-
? $priceRow['percentage_value']
156+
? (int)$priceRow['percentage_value']
153157
: null;
154158
}
155159

@@ -164,11 +168,14 @@ private function updateValues(array $valuesToUpdate, array $oldValues): bool
164168
{
165169
$isChanged = false;
166170
foreach ($valuesToUpdate as $key => $value) {
167-
if ((float)$oldValues[$key]['price'] !== (float)$value['value']) {
171+
if ((!empty($value['value']) && (float)$oldValues[$key]['price'] !== (float)$value['value'])
172+
|| $this->getPercentage($oldValues[$key]) !== $this->getPercentage($value)
173+
) {
168174
$price = new \Magento\Framework\DataObject(
169175
[
170176
'value_id' => $oldValues[$key]['price_id'],
171-
'value' => $value['value']
177+
'value' => $value['value'],
178+
'percentage_value' => $this->getPercentage($value)
172179
]
173180
);
174181
$this->tierPriceResource->savePriceData($price);
@@ -189,10 +196,11 @@ private function updateValues(array $valuesToUpdate, array $oldValues): bool
189196
private function insertValues(int $productId, array $valuesToInsert): bool
190197
{
191198
$isChanged = false;
199+
$identifierField = $this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField();
192200
foreach ($valuesToInsert as $data) {
193201
$price = new \Magento\Framework\DataObject($data);
194202
$price->setData(
195-
$this->metadataPoll->getMetadata(ProductInterface::class)->getLinkField(),
203+
$identifierField,
196204
$productId
197205
);
198206
$this->tierPriceResource->savePriceData($price);
@@ -246,7 +254,7 @@ private function getPriceKey(array $priceData): string
246254
private function prepareTierPrice(array $data): array
247255
{
248256
$useForAllGroups = (int)$data['cust_group'] === $this->groupManagement->getAllCustomersGroup()->getId();
249-
$customerGroupId = !$useForAllGroups ? $data['cust_group'] : 0;
257+
$customerGroupId = $useForAllGroups ? 0 : $data['cust_group'];
250258
$tierPrice = array_merge(
251259
$this->getAdditionalFields($data),
252260
[
@@ -264,11 +272,11 @@ private function prepareTierPrice(array $data): array
264272
/**
265273
* Check by id is website global
266274
*
267-
* @param string|int $websiteId
275+
* @param int $websiteId
268276
* @return bool
269277
*/
270-
private function isWebsiteGlobal($websiteId): bool
278+
private function isWebsiteGlobal(int $websiteId): bool
271279
{
272-
return (int)$websiteId === 0;
280+
return $websiteId === 0;
273281
}
274282
}

app/code/Magento/Catalog/etc/di.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -654,14 +654,14 @@
654654
<item name="mediaGalleryCreate" xsi:type="string">Magento\Catalog\Model\Product\Gallery\CreateHandler</item>
655655
<item name="categoryProductLinksSave" xsi:type="string">Magento\Catalog\Model\Category\Link\SaveHandler</item>
656656
<item name="websitePersistor" xsi:type="string">Magento\Catalog\Model\Product\Website\SaveHandler</item>
657-
<item name="tierPriceCreator" xsi:type="string">Magento\Catalog\Model\Product\TierPrice\SaveHandler</item>
657+
<item name="tierPriceCreator" xsi:type="string">Magento\Catalog\Model\Product\Attribute\Backend\TierPrice\SaveHandler</item>
658658
</item>
659659
<item name="update" xsi:type="array">
660660
<item name="optionUpdater" xsi:type="string">Magento\Catalog\Model\Product\Option\SaveHandler</item>
661661
<item name="mediaGalleryUpdate" xsi:type="string">Magento\Catalog\Model\Product\Gallery\UpdateHandler</item>
662662
<item name="categoryProductLinksSave" xsi:type="string">Magento\Catalog\Model\Category\Link\SaveHandler</item>
663663
<item name="websitePersistor" xsi:type="string">Magento\Catalog\Model\Product\Website\SaveHandler</item>
664-
<item name="tierPriceUpdater" xsi:type="string">Magento\Catalog\Model\Product\TierPrice\UpdateHandler</item>
664+
<item name="tierPriceUpdater" xsi:type="string">Magento\Catalog\Model\Product\Attribute\Backend\TierPrice\UpdateHandler</item>
665665
</item>
666666
</item>
667667
</argument>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Catalog\Model\Product\Attribute\Backend\TierPrice;
7+
8+
/**
9+
* Test class for \Magento\Catalog\Model\Product\Attribute\Backend\TierPrice\UpdateHandlerTest
10+
*
11+
* @magentoDataFixture Magento/Catalog/_files/product_simple.php
12+
*/
13+
class UpdateHandlerTest extends \PHPUnit\Framework\TestCase
14+
{
15+
/**
16+
* @var \Magento\Framework\EntityManager\MetadataPool
17+
*/
18+
protected $metadataPool;
19+
20+
/**
21+
* @var \Magento\Catalog\Model\ProductRepository
22+
*/
23+
protected $productRepository;
24+
25+
/**
26+
* @var \Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory
27+
*/
28+
private $tierPriceFactory;
29+
30+
/**
31+
* @inheritdoc
32+
*/
33+
protected function setUp()
34+
{
35+
$this->productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
36+
\Magento\Catalog\Model\ProductRepository::class
37+
);
38+
$this->tierPriceFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
39+
->create(\Magento\Catalog\Api\Data\ProductTierPriceInterfaceFactory::class);
40+
}
41+
42+
/**
43+
* @dataProvider afterSaveDataProvider
44+
* @param array $tierPricesData
45+
* @param int $isChanged
46+
* @param int $tierPriceCount
47+
* @throws \Magento\Framework\Exception\NoSuchEntityException
48+
*/
49+
public function testAfterSave(array $tierPricesData, $isChanged, $tierPriceCount)
50+
{
51+
/** @var $product \Magento\Catalog\Model\Product */
52+
$product = $this->productRepository->get('simple', true);
53+
$tierPrices = [];
54+
foreach ($tierPricesData as $tierPrice) {
55+
$tierPrices[] = $this->tierPriceFactory->create([
56+
'data' => $tierPrice
57+
]);
58+
}
59+
$product->setTierPrices($tierPrices);
60+
$product->save();
61+
$this->assertEquals($isChanged, $product->getData('tier_price_changed'));
62+
63+
/** @var $product \Magento\Catalog\Model\Product */
64+
$product = $this->productRepository->get('simple', true, null, true);
65+
$this->assertEquals($tierPriceCount, count($product->getTierPrice()));
66+
$this->assertEquals(0, $product->getData('tier_price_changed'));
67+
}
68+
69+
/**
70+
* @return array
71+
*/
72+
public function afterSaveDataProvider(): array
73+
{
74+
return [
75+
'same' => [
76+
[
77+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 2, 'value' => 8],
78+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5],
79+
['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5],
80+
[
81+
'website_id' => 0,
82+
'customer_group_id' => 0,
83+
'qty' => 10,
84+
'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
85+
],
86+
],
87+
0,
88+
4,
89+
],
90+
'update one' => [
91+
[
92+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 2, 'value' => 8],
93+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5],
94+
['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5],
95+
[
96+
'website_id' => 0,
97+
'customer_group_id' => 0,
98+
'qty' => 10,
99+
'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 10])
100+
],
101+
],
102+
1,
103+
4,
104+
],
105+
'delete one' => [
106+
[
107+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5],
108+
['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5],
109+
[
110+
'website_id' => 0,
111+
'customer_group_id' => 0,
112+
'qty' => 10,
113+
'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
114+
],
115+
],
116+
1,
117+
3,
118+
],
119+
'add one' => [
120+
[
121+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 2, 'value' => 8],
122+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 5, 'value' => 5],
123+
['website_id' => 0, 'customer_group_id' => 32000, 'qty' => 20, 'percentage_value' => 90],
124+
['website_id' => 0, 'customer_group_id' => 0, 'qty' => 3, 'value' => 5],
125+
[
126+
'website_id' => 0,
127+
'customer_group_id' => 0,
128+
'qty' => 10,
129+
'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
130+
],
131+
],
132+
1,
133+
5,
134+
],
135+
'delete all' => [[], 1, 0,],
136+
];
137+
}
138+
}

0 commit comments

Comments
 (0)