Skip to content

Commit 96bf912

Browse files
committed
ACP2E-465: Bundle product special price is not updated via REST API at store view scope
1 parent e349be1 commit 96bf912

File tree

3 files changed

+115
-9
lines changed

3 files changed

+115
-9
lines changed

app/code/Magento/Catalog/Model/Attribute/ScopeOverriddenValue.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use Magento\Framework\App\ResourceConnection;
1616

1717
/**
18-
* Class ScopeOverriddenValue
1918
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2019
*/
2120
class ScopeOverriddenValue
@@ -187,4 +186,14 @@ private function getAttributes($entityType)
187186
);
188187
return $searchResult->getItems();
189188
}
189+
190+
/**
191+
* Clear attributes values cache
192+
*
193+
* @return void
194+
*/
195+
public function clearAttributeValues(): void
196+
{
197+
$this->attributesValues = null;
198+
}
190199
}

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
*/
66
namespace Magento\Catalog\Model\ResourceModel;
77

8+
use Magento\Catalog\Api\Data\ProductInterface;
9+
use Magento\Catalog\Model\Attribute\ScopeOverriddenValue;
810
use Magento\Catalog\Model\ResourceModel\Product\Website\Link as ProductWebsiteLink;
911
use Magento\Eav\Api\AttributeManagementInterface;
1012
use Magento\Framework\App\ObjectManager;
@@ -40,15 +42,11 @@ class Product extends AbstractResource
4042
protected $_productCategoryTable;
4143

4244
/**
43-
* Catalog category
44-
*
4545
* @var Category
4646
*/
4747
protected $_catalogCategory;
4848

4949
/**
50-
* Category collection factory
51-
*
5250
* @var Category\CollectionFactory
5351
*/
5452
protected $_categoryCollectionFactory;
@@ -105,6 +103,11 @@ class Product extends AbstractResource
105103
*/
106104
private $mediaImageDeleteProcessor;
107105

106+
/**
107+
* @var ScopeOverriddenValue
108+
*/
109+
private $scopeOverriddenValue;
110+
108111
/**
109112
* @param \Magento\Eav\Model\Entity\Context $context
110113
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -120,6 +123,7 @@ class Product extends AbstractResource
120123
* @param UniqueValidationInterface|null $uniqueValidator
121124
* @param AttributeManagementInterface|null $eavAttributeManagement
122125
* @param MediaImageDeleteProcessor|null $mediaImageDeleteProcessor
126+
* @param ScopeOverriddenValue|null $scopeOverriddenValue
123127
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
124128
*/
125129
public function __construct(
@@ -136,7 +140,8 @@ public function __construct(
136140
TableMaintainer $tableMaintainer = null,
137141
UniqueValidationInterface $uniqueValidator = null,
138142
AttributeManagementInterface $eavAttributeManagement = null,
139-
?MediaImageDeleteProcessor $mediaImageDeleteProcessor = null
143+
?MediaImageDeleteProcessor $mediaImageDeleteProcessor = null,
144+
?ScopeOverriddenValue $scopeOverriddenValue = null
140145
) {
141146
$this->_categoryCollectionFactory = $categoryCollectionFactory;
142147
$this->_catalogCategory = $catalogCategory;
@@ -157,6 +162,8 @@ public function __construct(
157162
?? ObjectManager::getInstance()->get(AttributeManagementInterface::class);
158163
$this->mediaImageDeleteProcessor = $mediaImageDeleteProcessor
159164
?? ObjectManager::getInstance()->get(MediaImageDeleteProcessor::class);
165+
$this->scopeOverriddenValue = $scopeOverriddenValue
166+
?? ObjectManager::getInstance()->get(ScopeOverriddenValue::class);
160167
}
161168

162169
/**
@@ -316,6 +323,7 @@ protected function _afterSave(DataObject $product)
316323
{
317324
$this->removeNotInSetAttributeValues($product);
318325
$this->_saveWebsiteIds($product)->_saveCategories($product);
326+
$this->scopeOverriddenValue->clearAttributeValues();
319327
return parent::_afterSave($product);
320328
}
321329

dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryMultiWebsiteTest.php

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use Magento\Catalog\Api\Data\ProductInterface;
1111
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
1212
use Magento\Store\Model\Store;
13+
use Magento\TestFramework\Fixture\DataFixtureStorage;
14+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
1315
use Magento\TestFramework\Helper\Bootstrap;
1416
use Magento\TestFramework\TestCase\WebapiAbstract;
1517
use Magento\Catalog\Model\Attribute\ScopeOverriddenValue;
@@ -26,9 +28,9 @@
2628
*/
2729
class ProductRepositoryMultiWebsiteTest extends WebapiAbstract
2830
{
29-
const SERVICE_NAME = 'catalogProductRepositoryV1';
30-
const SERVICE_VERSION = 'V1';
31-
const RESOURCE_PATH = '/V1/products';
31+
private const SERVICE_NAME = 'catalogProductRepositoryV1';
32+
private const SERVICE_VERSION = 'V1';
33+
private const RESOURCE_PATH = '/V1/products';
3234

3335
/**
3436
* @var array
@@ -40,13 +42,19 @@ class ProductRepositoryMultiWebsiteTest extends WebapiAbstract
4042
*/
4143
private $objectManager;
4244

45+
/**
46+
* @var DataFixtureStorage
47+
*/
48+
private $fixtures;
49+
4350
/**
4451
* @inheritDoc
4552
*/
4653
protected function setUp(): void
4754
{
4855
parent::setUp();
4956
$this->objectManager = Bootstrap::getObjectManager();
57+
$this->fixtures = $this->objectManager->get(DataFixtureStorageManager::class)->getStorage();
5058
}
5159

5260
/**
@@ -329,6 +337,52 @@ public function testPartialUpdate(): void
329337
);
330338
}
331339

340+
/**
341+
* @magentoApiDataFixture Magento\Store\Test\Fixture\Website as:website2
342+
* @magentoApiDataFixture Magento\Store\Test\Fixture\Group with:{"website_id":"$website2.id$"} as:store_group2
343+
* @magentoApiDataFixture Magento\Store\Test\Fixture\Store with:{"store_group_id":"$store_group2.id$"} as:store2
344+
* @magentoApiDataFixture Magento\Store\Test\Fixture\Store with:{"store_group_id":"$store_group2.id$"} as:store3
345+
* @magentoApiDataFixture Magento\Catalog\Test\Fixture\Product with:{"website_ids":[1,"$website2.id$"]} as:product
346+
* @magentoConfigFixture catalog/price/scope 1
347+
*/
348+
public function testUpdatePrice(): void
349+
{
350+
$store = $this->objectManager->get(Store::class);
351+
$defaultWebsiteStore1 = $store->load('default', 'code')->getCode();
352+
$secondWebsiteStore1 = $this->fixtures->get('store2')->getCode();
353+
$secondWebsiteStore2 = $this->fixtures->get('store3')->getCode();
354+
$sku = $this->fixtures->get('product')->getSku();
355+
356+
// change any attribute value in second store
357+
$request = [
358+
ProductInterface::SKU => $sku,
359+
'name' => 'updated product name for storeview'
360+
];
361+
$this->saveProduct($request, $secondWebsiteStore1);
362+
363+
// now update prices in second website
364+
$request = [
365+
ProductInterface::SKU => $sku,
366+
'price' => 9,
367+
ProductInterface::CUSTOM_ATTRIBUTES => [
368+
[
369+
'attribute_code' => 'special_price',
370+
'value' => 8,
371+
]
372+
],
373+
];
374+
$this->saveProduct($request, $secondWebsiteStore1);
375+
$defaultWebsiteStore1Response = $this->flattenCustomAttributes($this->getProduct($sku, $defaultWebsiteStore1));
376+
$this->assertEquals(10, $defaultWebsiteStore1Response['price']);
377+
$this->assertArrayNotHasKey('special_price', $defaultWebsiteStore1Response);
378+
$secondWebsiteStore1Response = $this->flattenCustomAttributes($this->getProduct($sku, $secondWebsiteStore1));
379+
$this->assertEquals(9, $secondWebsiteStore1Response['price']);
380+
$this->assertEquals(8, $secondWebsiteStore1Response['special_price']);
381+
$secondWebsiteStore2Response = $this->flattenCustomAttributes($this->getProduct($sku, $secondWebsiteStore2));
382+
$this->assertEquals(9, $secondWebsiteStore2Response['price']);
383+
$this->assertEquals(8, $secondWebsiteStore2Response['special_price']);
384+
}
385+
332386
/**
333387
* @param array $expected
334388
* @param array $actual
@@ -381,4 +435,39 @@ private function updateAttribute(string $code, array $data): void
381435
$attribute->addData($data);
382436
$attributeRepository->save($attribute);
383437
}
438+
439+
/**
440+
* @param array $data
441+
* @return array
442+
*/
443+
private function flattenCustomAttributes(array $data): array
444+
{
445+
$customAttributes = $data[ProductInterface::CUSTOM_ATTRIBUTES] ?? [];
446+
unset($data[ProductInterface::CUSTOM_ATTRIBUTES]);
447+
return array_merge(array_column($customAttributes, 'value', 'attribute_code'), $data);
448+
}
449+
450+
/**
451+
* Get product
452+
*
453+
* @param string $sku
454+
* @param string|null $storeCode
455+
* @return array|bool|float|int|string
456+
*/
457+
private function getProduct($sku, $storeCode = null)
458+
{
459+
$serviceInfo = [
460+
'rest' => [
461+
'resourcePath' => self::RESOURCE_PATH . '/' . $sku,
462+
'httpMethod' => Request::HTTP_METHOD_GET,
463+
],
464+
'soap' => [
465+
'service' => self::SERVICE_NAME,
466+
'serviceVersion' => self::SERVICE_VERSION,
467+
'operation' => self::SERVICE_NAME . 'Get',
468+
],
469+
];
470+
471+
return $this->_webApiCall($serviceInfo, ['sku' => $sku], null, $storeCode);
472+
}
384473
}

0 commit comments

Comments
 (0)