Skip to content

Commit 188c570

Browse files
committed
Fix Price update API
1 parent 336eac0 commit 188c570

File tree

2 files changed

+160
-24
lines changed

2 files changed

+160
-24
lines changed

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

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,23 @@
66

77
namespace Magento\Catalog\Model\Product\Price;
88

9+
use Magento\Catalog\Api\BasePriceStorageInterface;
10+
use Magento\Catalog\Api\Data\BasePriceInterface;
11+
use Magento\Catalog\Api\Data\BasePriceInterfaceFactory;
12+
use Magento\Catalog\Api\ProductAttributeRepositoryInterface;
13+
use Magento\Catalog\Api\ProductRepositoryInterface;
14+
use Magento\Catalog\Model\Product\Price\Validation\InvalidSkuProcessor;
15+
use Magento\Catalog\Model\Product\Price\Validation\Result;
16+
use Magento\Catalog\Model\ProductIdLocatorInterface;
17+
use Magento\Framework\App\ObjectManager;
18+
use Magento\Framework\Exception\NoSuchEntityException;
19+
use Magento\Store\Api\StoreRepositoryInterface;
20+
use Magento\Store\Model\Store;
21+
922
/**
1023
* Base prices storage.
1124
*/
12-
class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
25+
class BasePriceStorage implements BasePriceStorageInterface
1326
{
1427
/**
1528
* Attribute code.
@@ -24,27 +37,27 @@ class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
2437
private $pricePersistence;
2538

2639
/**
27-
* @var \Magento\Catalog\Api\Data\BasePriceInterfaceFactory
40+
* @var BasePriceInterfaceFactory
2841
*/
2942
private $basePriceInterfaceFactory;
3043

3144
/**
32-
* @var \Magento\Catalog\Model\ProductIdLocatorInterface
45+
* @var ProductIdLocatorInterface
3346
*/
3447
private $productIdLocator;
3548

3649
/**
37-
* @var \Magento\Store\Api\StoreRepositoryInterface
50+
* @var StoreRepositoryInterface
3851
*/
3952
private $storeRepository;
4053

4154
/**
42-
* @var \Magento\Catalog\Api\ProductRepositoryInterface
55+
* @var ProductRepositoryInterface
4356
*/
4457
private $productRepository;
4558

4659
/**
47-
* @var \Magento\Catalog\Model\Product\Price\Validation\Result
60+
* @var Result
4861
*/
4962
private $validationResult;
5063

@@ -54,10 +67,15 @@ class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
5467
private $pricePersistenceFactory;
5568

5669
/**
57-
* @var \Magento\Catalog\Model\Product\Price\Validation\InvalidSkuProcessor
70+
* @var InvalidSkuProcessor
5871
*/
5972
private $invalidSkuProcessor;
6073

74+
/**
75+
* @var ProductAttributeRepositoryInterface
76+
*/
77+
private $productAttributeRepository;
78+
6179
/**
6280
* Price type allowed.
6381
*
@@ -74,23 +92,25 @@ class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
7492

7593
/**
7694
* @param PricePersistenceFactory $pricePersistenceFactory
77-
* @param \Magento\Catalog\Api\Data\BasePriceInterfaceFactory $basePriceInterfaceFactory
78-
* @param \Magento\Catalog\Model\ProductIdLocatorInterface $productIdLocator
79-
* @param \Magento\Store\Api\StoreRepositoryInterface $storeRepository
80-
* @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
81-
* @param \Magento\Catalog\Model\Product\Price\Validation\Result $validationResult
82-
* @param \Magento\Catalog\Model\Product\Price\Validation\InvalidSkuProcessor $invalidSkuProcessor
95+
* @param BasePriceInterfaceFactory $basePriceInterfaceFactory
96+
* @param ProductIdLocatorInterface $productIdLocator
97+
* @param StoreRepositoryInterface $storeRepository
98+
* @param ProductRepositoryInterface $productRepository
99+
* @param Result $validationResult
100+
* @param InvalidSkuProcessor $invalidSkuProcessor
101+
* @param ProductAttributeRepositoryInterface|null $productAttributeRepository
83102
* @param array $allowedProductTypes [optional]
84103
*/
85104
public function __construct(
86105
PricePersistenceFactory $pricePersistenceFactory,
87-
\Magento\Catalog\Api\Data\BasePriceInterfaceFactory $basePriceInterfaceFactory,
88-
\Magento\Catalog\Model\ProductIdLocatorInterface $productIdLocator,
89-
\Magento\Store\Api\StoreRepositoryInterface $storeRepository,
90-
\Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
91-
\Magento\Catalog\Model\Product\Price\Validation\Result $validationResult,
92-
\Magento\Catalog\Model\Product\Price\Validation\InvalidSkuProcessor $invalidSkuProcessor,
93-
array $allowedProductTypes = []
106+
BasePriceInterfaceFactory $basePriceInterfaceFactory,
107+
ProductIdLocatorInterface $productIdLocator,
108+
StoreRepositoryInterface $storeRepository,
109+
ProductRepositoryInterface $productRepository,
110+
Result $validationResult,
111+
InvalidSkuProcessor $invalidSkuProcessor,
112+
array $allowedProductTypes = [],
113+
ProductAttributeRepositoryInterface $productAttributeRepository = null
94114
) {
95115
$this->pricePersistenceFactory = $pricePersistenceFactory;
96116
$this->basePriceInterfaceFactory = $basePriceInterfaceFactory;
@@ -100,10 +120,12 @@ public function __construct(
100120
$this->validationResult = $validationResult;
101121
$this->allowedProductTypes = $allowedProductTypes;
102122
$this->invalidSkuProcessor = $invalidSkuProcessor;
123+
$this->productAttributeRepository = $productAttributeRepository ?: ObjectManager::getInstance()
124+
->get(ProductAttributeRepositoryInterface::class);
103125
}
104126

105127
/**
106-
* {@inheritdoc}
128+
* @inheritdoc
107129
*/
108130
public function get(array $skus)
109131
{
@@ -128,7 +150,7 @@ public function get(array $skus)
128150
}
129151

130152
/**
131-
* {@inheritdoc}
153+
* @inheritdoc
132154
*/
133155
public function update(array $prices)
134156
{
@@ -146,6 +168,12 @@ public function update(array $prices)
146168
}
147169
}
148170

171+
$priceAttribute = $this->productAttributeRepository->get($this->attributeCode);
172+
173+
if ($priceAttribute !== null && $priceAttribute->isScopeWebsite()) {
174+
$formattedPrices = $this->applyWebsitePrices($formattedPrices);
175+
}
176+
149177
$this->getPricePersistence()->update($formattedPrices);
150178

151179
return $this->validationResult->getFailedItems();
@@ -168,7 +196,7 @@ private function getPricePersistence()
168196
/**
169197
* Retrieve valid prices that do not contain any errors.
170198
*
171-
* @param \Magento\Catalog\Api\Data\BasePriceInterface[] $prices
199+
* @param BasePriceInterface[] $prices
172200
* @return array
173201
*/
174202
private function retrieveValidPrices(array $prices)
@@ -207,7 +235,7 @@ private function retrieveValidPrices(array $prices)
207235
}
208236
try {
209237
$this->storeRepository->getById($price->getStoreId());
210-
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
238+
} catch (NoSuchEntityException $e) {
211239
$this->validationResult->addFailedItem(
212240
$id,
213241
__(
@@ -225,4 +253,32 @@ private function retrieveValidPrices(array $prices)
225253

226254
return $prices;
227255
}
256+
257+
/**
258+
* If Catalog Price Mode is Website, price needs to be applied to all Store Views in this website.
259+
*
260+
* @param array $formattedPrices
261+
* @return array
262+
* @throws NoSuchEntityException
263+
*/
264+
private function applyWebsitePrices($formattedPrices): array
265+
{
266+
foreach ($formattedPrices as $price) {
267+
if ($price['store_id'] == Store::DEFAULT_STORE_ID) {
268+
continue;
269+
}
270+
271+
$storeIds = $this->storeRepository->getById($price['store_id'])->getWebsite()->getStoreIds();
272+
273+
// Unset origin store view to get rid of duplicate
274+
unset($storeIds[$price['store_id']]);
275+
276+
foreach ($storeIds as $storeId) {
277+
$price['store_id'] = (int)$storeId;
278+
$formattedPrices[] = $price;
279+
}
280+
}
281+
282+
return $formattedPrices;
283+
}
228284
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\Catalog\Api;
8+
9+
use Magento\TestFramework\Helper\Bootstrap;
10+
use Magento\TestFramework\TestCase\WebapiAbstract;
11+
12+
class ProductRepositoryPriceModeWebsiteChangePriceTest extends WebapiAbstract
13+
{
14+
const SERVICE_NAME = 'catalogProductRepositoryV1';
15+
const SERVICE_VERSION = 'V1';
16+
const PRODUCTS_RESOURCE_PATH = '/V1/products';
17+
const PRICES_RESOURCE_PATH = '/V1/products/base-prices';
18+
const STORE1_CODE_FROM_FIXTURE = 'fixturestore';
19+
const STORE2_CODE_FROM_FIXTURE = 'fixture_second_store';
20+
21+
/**
22+
* @magentoApiDataFixture Magento/Store/_files/core_fixturestore.php
23+
* @magentoApiDataFixture Magento/Store/_files/second_store.php
24+
* @magentoApiDataFixture Magento/CatalogSearch/_files/full_reindex.php
25+
* @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
26+
* @magentoConfigFixture admin_store catalog/price/scope 1
27+
*/
28+
public function testChangePriceForStore()
29+
{
30+
/** @var $store1 \Magento\Store\Model\Group */
31+
$store1 = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
32+
$store1->load(self::STORE1_CODE_FROM_FIXTURE);
33+
34+
/** @var $store2 \Magento\Store\Model\Group */
35+
$store2 = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
36+
$store2->load(self::STORE2_CODE_FROM_FIXTURE);
37+
38+
$sku = 'simple';
39+
40+
$requestData1 = [
41+
'prices' => [
42+
[
43+
'price' => 20,
44+
'store_id' => $store1->getId(),
45+
'sku' => $sku
46+
]
47+
]
48+
];
49+
50+
$requestData2 = [
51+
'prices' => [
52+
[
53+
'price' => 30,
54+
'store_id' => $store2->getId(),
55+
'sku' => $sku
56+
]
57+
]
58+
];
59+
60+
$serviceInfo = [
61+
'rest' => [
62+
'resourcePath' => self::PRICES_RESOURCE_PATH,
63+
'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST
64+
]
65+
];
66+
67+
$this->_webApiCall($serviceInfo, $requestData1);
68+
$this->_webApiCall($serviceInfo, $requestData2);
69+
70+
/** @var \Magento\Catalog\Model\ProductRepository $productRepository */
71+
$productRepository = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\ProductRepository::class);
72+
$product = $productRepository->get($sku, false, $store1->getId());
73+
74+
$this->assertEquals(
75+
$product->getPrice(),
76+
30,
77+
'Product prices for Website Price mode is invalid.'
78+
);
79+
}
80+
}

0 commit comments

Comments
 (0)