Skip to content

Commit d67dd12

Browse files
committed
Merge branch 'base-price-storage-website-price' of github.com:wassuupp/magento2 into 2.4-develop
2 parents 83f3d01 + 611aefa commit d67dd12

File tree

10 files changed

+256
-49
lines changed

10 files changed

+256
-49
lines changed

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

Lines changed: 81 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,24 @@
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.
24+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1125
*/
12-
class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
26+
class BasePriceStorage implements BasePriceStorageInterface
1327
{
1428
/**
1529
* Attribute code.
@@ -24,27 +38,27 @@ class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
2438
private $pricePersistence;
2539

2640
/**
27-
* @var \Magento\Catalog\Api\Data\BasePriceInterfaceFactory
41+
* @var BasePriceInterfaceFactory
2842
*/
2943
private $basePriceInterfaceFactory;
3044

3145
/**
32-
* @var \Magento\Catalog\Model\ProductIdLocatorInterface
46+
* @var ProductIdLocatorInterface
3347
*/
3448
private $productIdLocator;
3549

3650
/**
37-
* @var \Magento\Store\Api\StoreRepositoryInterface
51+
* @var StoreRepositoryInterface
3852
*/
3953
private $storeRepository;
4054

4155
/**
42-
* @var \Magento\Catalog\Api\ProductRepositoryInterface
56+
* @var ProductRepositoryInterface
4357
*/
4458
private $productRepository;
4559

4660
/**
47-
* @var \Magento\Catalog\Model\Product\Price\Validation\Result
61+
* @var Result
4862
*/
4963
private $validationResult;
5064

@@ -54,10 +68,15 @@ class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
5468
private $pricePersistenceFactory;
5569

5670
/**
57-
* @var \Magento\Catalog\Model\Product\Price\Validation\InvalidSkuProcessor
71+
* @var InvalidSkuProcessor
5872
*/
5973
private $invalidSkuProcessor;
6074

75+
/**
76+
* @var ProductAttributeRepositoryInterface
77+
*/
78+
private $productAttributeRepository;
79+
6180
/**
6281
* Price type allowed.
6382
*
@@ -74,23 +93,25 @@ class BasePriceStorage implements \Magento\Catalog\Api\BasePriceStorageInterface
7493

7594
/**
7695
* @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
96+
* @param BasePriceInterfaceFactory $basePriceInterfaceFactory
97+
* @param ProductIdLocatorInterface $productIdLocator
98+
* @param StoreRepositoryInterface $storeRepository
99+
* @param ProductRepositoryInterface $productRepository
100+
* @param Result $validationResult
101+
* @param InvalidSkuProcessor $invalidSkuProcessor
83102
* @param array $allowedProductTypes [optional]
103+
* @param ProductAttributeRepositoryInterface|null $productAttributeRepository
84104
*/
85105
public function __construct(
86106
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 = []
107+
BasePriceInterfaceFactory $basePriceInterfaceFactory,
108+
ProductIdLocatorInterface $productIdLocator,
109+
StoreRepositoryInterface $storeRepository,
110+
ProductRepositoryInterface $productRepository,
111+
Result $validationResult,
112+
InvalidSkuProcessor $invalidSkuProcessor,
113+
array $allowedProductTypes = [],
114+
ProductAttributeRepositoryInterface $productAttributeRepository = null
94115
) {
95116
$this->pricePersistenceFactory = $pricePersistenceFactory;
96117
$this->basePriceInterfaceFactory = $basePriceInterfaceFactory;
@@ -100,10 +121,12 @@ public function __construct(
100121
$this->validationResult = $validationResult;
101122
$this->allowedProductTypes = $allowedProductTypes;
102123
$this->invalidSkuProcessor = $invalidSkuProcessor;
124+
$this->productAttributeRepository = $productAttributeRepository ?: ObjectManager::getInstance()
125+
->get(ProductAttributeRepositoryInterface::class);
103126
}
104127

105128
/**
106-
* {@inheritdoc}
129+
* @inheritdoc
107130
*/
108131
public function get(array $skus)
109132
{
@@ -128,7 +151,7 @@ public function get(array $skus)
128151
}
129152

130153
/**
131-
* {@inheritdoc}
154+
* @inheritdoc
132155
*/
133156
public function update(array $prices)
134157
{
@@ -146,6 +169,12 @@ public function update(array $prices)
146169
}
147170
}
148171

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

151180
return $this->validationResult->getFailedItems();
@@ -168,7 +197,7 @@ private function getPricePersistence()
168197
/**
169198
* Retrieve valid prices that do not contain any errors.
170199
*
171-
* @param \Magento\Catalog\Api\Data\BasePriceInterface[] $prices
200+
* @param BasePriceInterface[] $prices
172201
* @return array
173202
*/
174203
private function retrieveValidPrices(array $prices)
@@ -207,7 +236,7 @@ private function retrieveValidPrices(array $prices)
207236
}
208237
try {
209238
$this->storeRepository->getById($price->getStoreId());
210-
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
239+
} catch (NoSuchEntityException $e) {
211240
$this->validationResult->addFailedItem(
212241
$id,
213242
__(
@@ -225,4 +254,32 @@ private function retrieveValidPrices(array $prices)
225254

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

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
use Magento\TestFramework\TestCase\WebapiAbstract;
1111

1212
/**
13-
* Class ProductTierPriceManagementTest
14-
*
15-
* @package Magento\Catalog\Api
13+
* ProductTierPriceManagementTest API operations test
1614
*/
1715
class ProductTierPriceManagementTest extends WebapiAbstract
1816
{
@@ -82,7 +80,7 @@ public function testDelete($customerGroupId, $qty)
8280
],
8381
];
8482
$requestData = ['sku' => $productSku, 'customerGroupId' => $customerGroupId, 'qty' => $qty];
85-
$this->assertTrue($this->_webApiCall($serviceInfo, $requestData));
83+
$this->assertTrue($this->_webApiCall($serviceInfo, $requestData, null, "all"));
8684
}
8785

8886
public function deleteDataProvider()
@@ -198,7 +196,7 @@ public function testUpdateWithAllGroups()
198196
'qty' => $qty,
199197
'price' => $price,
200198
];
201-
$this->_webApiCall($serviceInfo, $requestData);
199+
$this->_webApiCall($serviceInfo, $requestData, null, "all");
202200
$objectManager = \Magento\TestFramework\ObjectManager::getInstance();
203201
/** @var \Magento\Catalog\Api\ProductTierPriceManagementInterface $service */
204202
$service = $objectManager->get(\Magento\Catalog\Api\ProductTierPriceManagementInterface::class);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public function testUpdate(array $data)
148148
* Delete special price for specified store when price scope is global
149149
*
150150
* @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
151-
*
151+
* @magentoConfigFixture default_store catalog/price/scope 0
152152
* @return void
153153
*/
154154
public function testDeleteWhenPriceIsGlobal(): void

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Magento\TestFramework\TestCase\WebapiAbstract;
99

1010
/**
11-
* TierPriceStorage test.
11+
* TierPriceStorage API operations test.
1212
*/
1313
class TierPriceStorageTest extends WebapiAbstract
1414
{
@@ -33,6 +33,7 @@ protected function setUp(): void
3333
* Test get method.
3434
*
3535
* @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
36+
* @magentoConfigFixture default_store catalog/price/scope 0
3637
*/
3738
public function testGet()
3839
{
@@ -53,7 +54,6 @@ public function testGet()
5354
$tierPrices = $productRepository->get(self::SIMPLE_PRODUCT_SKU)->getTierPrices();
5455
$this->assertNotEmpty($response);
5556
$this->assertEquals(count($response), count($tierPrices));
56-
5757
foreach ($response as $item) {
5858
$this->assertTrue($this->isPriceCorrect($item, $tierPrices));
5959
}
@@ -63,6 +63,7 @@ public function testGet()
6363
* Test update method.
6464
*
6565
* @magentoApiDataFixture Magento/Catalog/_files/product_simple.php
66+
* @magentoConfigFixture default_store catalog/price/scope 0
6667
*/
6768
public function testUpdate()
6869
{
@@ -252,7 +253,6 @@ public function testDelete()
252253
private function isPriceCorrect(array $price, array $tierPrices)
253254
{
254255
$isCorrect = false;
255-
256256
foreach ($tierPrices as $tierPrice) {
257257
$priceIsCorrect = $price['price_type'] === \Magento\Catalog\Api\Data\TierPriceInterface::PRICE_TYPE_DISCOUNT
258258
? (float)$tierPrice->getExtensionAttributes()->getPercentageValue() === (float)$price['price']
@@ -265,7 +265,6 @@ private function isPriceCorrect(array $price, array $tierPrices)
265265
break;
266266
}
267267
}
268-
269268
return $isCorrect;
270269
}
271270
}

0 commit comments

Comments
 (0)