Skip to content

Commit 82fa678

Browse files
committed
Merge remote-tracking branch 'origin/MAGETWO-72875' into 2.3-develop-pr9
2 parents 0cba9b4 + 2ab14c2 commit 82fa678

File tree

19 files changed

+308
-121
lines changed

19 files changed

+308
-121
lines changed

app/code/Magento/Bundle/Pricing/Price/BundleRegularPrice.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function getAmount()
5252
if ($this->product->getPriceType() == Price::PRICE_TYPE_FIXED) {
5353
/** @var \Magento\Catalog\Pricing\Price\CustomOptionPrice $customOptionPrice */
5454
$customOptionPrice = $this->priceInfo->getPrice(CustomOptionPrice::PRICE_CODE);
55-
$price += $customOptionPrice->getCustomOptionRange(true);
55+
$price += $customOptionPrice->getCustomOptionRange(true, $this->getPriceCode());
5656
}
5757
$this->amount[$this->getValue()] = $this->calculator->getMinRegularAmount($price, $this->product);
5858
}
@@ -71,7 +71,7 @@ public function getMaximalPrice()
7171
if ($this->product->getPriceType() == Price::PRICE_TYPE_FIXED) {
7272
/** @var \Magento\Catalog\Pricing\Price\CustomOptionPrice $customOptionPrice */
7373
$customOptionPrice = $this->priceInfo->getPrice(CustomOptionPrice::PRICE_CODE);
74-
$price += $customOptionPrice->getCustomOptionRange(false);
74+
$price += $customOptionPrice->getCustomOptionRange(false, $this->getPriceCode());
7575
}
7676
$this->maximalPrice = $this->calculator->getMaxRegularAmount($price, $this->product);
7777
}

app/code/Magento/Bundle/Pricing/Price/BundleSelectionPrice.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ public function getValue()
128128
'catalog_product_get_final_price',
129129
['product' => $product, 'qty' => $this->bundleProduct->getQty()]
130130
);
131-
$value = $product->getData('final_price') * ($selectionPriceValue / 100);
131+
$price = $this->useRegularPrice ? $product->getData('price') : $product->getData('final_price');
132+
$value = $price * ($selectionPriceValue / 100);
132133
} else {
133134
// calculate price for selection type fixed
134135
$value = $this->priceCurrency->convert($selectionPriceValue);

app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ public function testGetValueTypeFixedWithSelectionPriceType($useRegularPrice)
201201
[
202202
['qty', null, 1],
203203
['final_price', null, 100],
204+
['price', null, 100],
204205
]
205206
)
206207
);

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ public function getUpdatedAt()
625625
*
626626
* @param bool $calculate
627627
* @return void
628+
* @deprecated
628629
*/
629630
public function setPriceCalculation($calculate = true)
630631
{
@@ -1174,10 +1175,11 @@ public function setFinalPrice($price)
11741175
*/
11751176
public function getFinalPrice($qty = null)
11761177
{
1177-
if ($this->_getData('final_price') === null) {
1178-
$this->setFinalPrice($this->getPriceModel()->getFinalPrice($qty, $this));
1178+
if ($this->_calculatePrice || $this->_getData('final_price') === null) {
1179+
return $this->getPriceModel()->getFinalPrice($qty, $this);
1180+
} else {
1181+
return $this->_getData('final_price');
11791182
}
1180-
return $this->_getData('final_price');
11811183
}
11821184

11831185
/**

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

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88

99
use Magento\Catalog\Model\Product;
1010
use Magento\Catalog\Model\Product\Option;
11-
use Magento\Catalog\Pricing\Price\BasePrice;
1211
use Magento\Framework\Model\AbstractModel;
12+
use Magento\Catalog\Pricing\Price\BasePrice;
13+
use Magento\Catalog\Pricing\Price\CustomOptionPriceCalculator;
14+
use Magento\Catalog\Pricing\Price\RegularPrice;
1315

1416
/**
1517
* Catalog product option select type model
@@ -19,6 +21,9 @@
1921
* @method \Magento\Catalog\Model\Product\Option\Value setOptionId(int $value)
2022
*
2123
* @SuppressWarnings(PHPMD.LongVariable)
24+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) - added use of constants instead of string literals:
25+
* BasePrice::PRICE_CODE - instead of 'base_price'
26+
* RegularPrice::PRICE_CODE - instead of 'regular_price'
2227
* @since 100.0.2
2328
*/
2429
class Value extends AbstractModel implements \Magento\Catalog\Api\Data\ProductCustomOptionValuesInterface
@@ -59,6 +64,11 @@ class Value extends AbstractModel implements \Magento\Catalog\Api\Data\ProductCu
5964
*/
6065
protected $_valueCollectionFactory;
6166

67+
/**
68+
* @var CustomOptionPriceCalculator
69+
*/
70+
private $customOptionPriceCalculator;
71+
6272
/**
6373
* @param \Magento\Framework\Model\Context $context
6474
* @param \Magento\Framework\Registry $registry
@@ -73,9 +83,12 @@ public function __construct(
7383
\Magento\Catalog\Model\ResourceModel\Product\Option\Value\CollectionFactory $valueCollectionFactory,
7484
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
7585
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
76-
array $data = []
86+
array $data = [],
87+
CustomOptionPriceCalculator $customOptionPriceCalculator = null
7788
) {
7889
$this->_valueCollectionFactory = $valueCollectionFactory;
90+
$this->customOptionPriceCalculator = $customOptionPriceCalculator
91+
?? \Magento\Framework\App\ObjectManager::getInstance()->get(CustomOptionPriceCalculator::class);
7992
parent::__construct(
8093
$context,
8194
$registry,
@@ -222,10 +235,8 @@ public function saveValues()
222235
*/
223236
public function getPrice($flag = false)
224237
{
225-
if ($flag && $this->getPriceType() == self::TYPE_PERCENT) {
226-
$basePrice = $this->getOption()->getProduct()->getPriceInfo()->getPrice(BasePrice::PRICE_CODE)->getValue();
227-
$price = $basePrice * ($this->_getData(self::KEY_PRICE) / 100);
228-
return $price;
238+
if ($flag) {
239+
return $this->customOptionPriceCalculator->getOptionPriceByPriceCode($this, BasePrice::PRICE_CODE);
229240
}
230241
return $this->_getData(self::KEY_PRICE);
231242
}
@@ -237,13 +248,7 @@ public function getPrice($flag = false)
237248
*/
238249
public function getRegularPrice()
239250
{
240-
if ($this->getPriceType() == self::TYPE_PERCENT) {
241-
$basePrice = $this->getOption()->getProduct()->getPriceInfo()
242-
->getPrice('regular_price')->getAmount()->getValue();
243-
$price = $basePrice * ($this->_getData(self::KEY_PRICE) / 100);
244-
return $price;
245-
}
246-
return $this->_getData(self::KEY_PRICE);
251+
return $this->customOptionPriceCalculator->getOptionPriceByPriceCode($this, RegularPrice::PRICE_CODE);
247252
}
248253

249254
/**

app/code/Magento/Catalog/Pricing/Price/CustomOptionPrice.php

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,42 @@ class CustomOptionPrice extends AbstractPrice implements CustomOptionPriceInterf
3535
*/
3636
protected $excludeAdjustment = null;
3737

38+
/**
39+
* @var CustomOptionPriceCalculator
40+
*/
41+
private $customOptionPriceCalculator;
42+
3843
/**
3944
* @param SaleableInterface $saleableItem
4045
* @param float $quantity
4146
* @param CalculatorInterface $calculator
4247
* @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
43-
* @param array $excludeAdjustment
48+
* @param array|null $excludeAdjustment
49+
* @param CustomOptionPriceCalculator|null $customOptionPriceCalculator
4450
*/
4551
public function __construct(
4652
SaleableInterface $saleableItem,
4753
$quantity,
4854
CalculatorInterface $calculator,
4955
\Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency,
50-
$excludeAdjustment = null
56+
$excludeAdjustment = null,
57+
CustomOptionPriceCalculator $customOptionPriceCalculator = null
5158
) {
5259
parent::__construct($saleableItem, $quantity, $calculator, $priceCurrency);
5360
$this->excludeAdjustment = $excludeAdjustment;
61+
$this->customOptionPriceCalculator = $customOptionPriceCalculator
62+
?? \Magento\Framework\App\ObjectManager::getInstance()->get(CustomOptionPriceCalculator::class);
5463
}
5564

5665
/**
57-
* Get minimal and maximal option values
66+
* Get minimal and maximal option values.
5867
*
68+
* @param string $priceCode
5969
* @return array
6070
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
6171
* @SuppressWarnings(PHPMD.NPathComplexity)
6272
*/
63-
public function getValue()
73+
public function getValue($priceCode = \Magento\Catalog\Pricing\Price\BasePrice::PRICE_CODE)
6474
{
6575
$optionValues = [];
6676
$options = $this->product->getOptions();
@@ -85,7 +95,8 @@ public function getValue()
8595
} else {
8696
/** @var $optionValue \Magento\Catalog\Model\Product\Option\Value */
8797
foreach ($optionItem->getValues() as $optionValue) {
88-
$price = $optionValue->getPrice($optionValue->getPriceType() == Value::TYPE_PERCENT);
98+
$price =
99+
$this->customOptionPriceCalculator->getOptionPriceByPriceCode($optionValue, $priceCode);
89100
if ($min === null) {
90101
$min = $price;
91102
} elseif ($price < $min) {
@@ -130,15 +141,16 @@ public function getCustomAmount($amount = null, $exclude = null, $context = [])
130141
}
131142

132143
/**
133-
* Return the minimal or maximal price for custom options
144+
* Return the minimal or maximal price for custom options.
134145
*
135146
* @param bool $getMin
147+
* @param string $priceCode
136148
* @return float
137149
*/
138-
public function getCustomOptionRange($getMin)
150+
public function getCustomOptionRange($getMin, $priceCode = \Magento\Catalog\Pricing\Price\BasePrice::PRICE_CODE)
139151
{
140152
$optionValue = 0.;
141-
$options = $this->getValue();
153+
$options = $this->getValue($priceCode);
142154
foreach ($options as $option) {
143155
if ($getMin) {
144156
$optionValue += $option['min'];
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Catalog\Pricing\Price;
9+
10+
use Magento\Catalog\Model\Product\Option\Value as ProductOptionValue;
11+
12+
/**
13+
* Calculates prices of custom options of the product.
14+
*/
15+
class CustomOptionPriceCalculator
16+
{
17+
/**
18+
* Calculates prices of custom option by code.
19+
*
20+
* Price is calculated depends on Price Code.
21+
* Existing logic was taken from methods \Magento\Catalog\Model\Product\Option\Value::(getPrice|getRegularPrice)
22+
* where $priceCode was hardcoded and changed to have dynamical approach.
23+
*
24+
* Examples of usage:
25+
* \Magento\Catalog\Pricing\Price\CustomOptionPrice::getValue
26+
* \Magento\Catalog\Model\Product\Option\Value::getPrice
27+
* \Magento\Catalog\Model\Product\Option\Value::getRegularPrice
28+
*
29+
* @param ProductOptionValue $optionValue
30+
* @param string $priceCode
31+
* @return float|int
32+
*/
33+
public function getOptionPriceByPriceCode(
34+
ProductOptionValue $optionValue,
35+
string $priceCode = BasePrice::PRICE_CODE
36+
) {
37+
if ($optionValue->getPriceType() === ProductOptionValue::TYPE_PERCENT) {
38+
$basePrice = $optionValue->getOption()->getProduct()->getPriceInfo()->getPrice($priceCode)->getValue();
39+
$price = $basePrice * ($optionValue->getData(ProductOptionValue::KEY_PRICE) / 100);
40+
41+
return $price;
42+
}
43+
44+
return $optionValue->getData(ProductOptionValue::KEY_PRICE);
45+
}
46+
}

app/code/Magento/Catalog/Test/Unit/Model/Product/Option/ValueTest.php

Lines changed: 34 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,32 @@ class ValueTest extends \PHPUnit\Framework\TestCase
1919
*/
2020
private $model;
2121

22+
/**
23+
* @var \Magento\Catalog\Pricing\Price\CustomOptionPriceCalculator
24+
*/
25+
private $customOptionPriceCalculatorMock;
26+
27+
protected function setUp()
28+
{
29+
$mockedResource = $this->getMockedResource();
30+
$mockedCollectionFactory = $this->getMockedValueCollectionFactory();
31+
32+
$this->customOptionPriceCalculatorMock = $this->createMock(
33+
\Magento\Catalog\Pricing\Price\CustomOptionPriceCalculator::class
34+
);
35+
36+
$helper = new ObjectManager($this);
37+
$this->model = $helper->getObject(
38+
\Magento\Catalog\Model\Product\Option\Value::class,
39+
[
40+
'resource' => $mockedResource,
41+
'valueCollectionFactory' => $mockedCollectionFactory,
42+
'customOptionPriceCalculator' => $this->customOptionPriceCalculatorMock,
43+
]
44+
);
45+
$this->model->setOption($this->getMockedOption());
46+
}
47+
2248
public function testSaveProduct()
2349
{
2450
$this->model->setValues([100])
@@ -35,11 +61,16 @@ public function testSaveProduct()
3561

3662
public function testGetPrice()
3763
{
38-
$this->model->setPrice(1000);
64+
$price = 1000;
65+
$this->model->setPrice($price);
3966
$this->model->setPriceType(Value::TYPE_PERCENT);
40-
$this->assertEquals(1000, $this->model->getPrice(false));
67+
$this->assertEquals($price, $this->model->getPrice(false));
4168

42-
$this->assertEquals(100, $this->model->getPrice(true));
69+
$percentPice = 100;
70+
$this->customOptionPriceCalculatorMock->expects($this->atLeastOnce())
71+
->method('getOptionPriceByPriceCode')
72+
->willReturn($percentPice);
73+
$this->assertEquals($percentPice, $this->model->getPrice(true));
4374
}
4475

4576
public function testGetValuesCollection()
@@ -78,23 +109,6 @@ public function testDeleteValue()
78109
$this->assertInstanceOf(\Magento\Catalog\Model\Product\Option\Value::class, $this->model->deleteValue(1));
79110
}
80111

81-
protected function setUp()
82-
{
83-
$mockedResource = $this->getMockedResource();
84-
$mockedCollectionFactory = $this->getMockedValueCollectionFactory();
85-
$mockedContext = $this->getMockedContext();
86-
$helper = new ObjectManager($this);
87-
$this->model = $helper->getObject(
88-
\Magento\Catalog\Model\Product\Option\Value::class,
89-
[
90-
'resource' => $mockedResource,
91-
'valueCollectionFactory' => $mockedCollectionFactory,
92-
'context' => $mockedContext
93-
]
94-
);
95-
$this->model->setOption($this->getMockedOption());
96-
}
97-
98112
/**
99113
* @return \Magento\Catalog\Model\ResourceModel\Product\Option\Value\CollectionFactory
100114
*/
@@ -243,61 +257,4 @@ private function getMockedResource()
243257

244258
return $mock;
245259
}
246-
247-
/**
248-
* @return \Magento\Framework\Model\Context
249-
*/
250-
private function getMockedContext()
251-
{
252-
$mockedRemoveAction = $this->getMockedRemoveAction();
253-
$mockEventManager = $this->getMockedEventManager();
254-
255-
$mockBuilder = $this->getMockBuilder(\Magento\Framework\Model\Context::class)
256-
->setMethods(['getActionValidator', 'getEventDispatcher'])
257-
->disableOriginalConstructor();
258-
$mock = $mockBuilder->getMock();
259-
260-
$mock->expects($this->any())
261-
->method('getActionValidator')
262-
->will($this->returnValue($mockedRemoveAction));
263-
264-
$mock->expects($this->any())
265-
->method('getEventDispatcher')
266-
->will($this->returnValue($mockEventManager));
267-
268-
return $mock;
269-
}
270-
271-
/**
272-
* @return RemoveAction
273-
*/
274-
private function getMockedRemoveAction()
275-
{
276-
$mockBuilder = $this->getMockBuilder(\Magento\Framework\Model\Context::class)
277-
->setMethods(['isAllowed'])
278-
->disableOriginalConstructor();
279-
$mock = $mockBuilder->getMock();
280-
281-
$mock->expects($this->any())
282-
->method('isAllowed')
283-
->will($this->returnValue(true));
284-
285-
return $mock;
286-
}
287-
288-
/**
289-
* @return \Magento\Framework\Event\ManagerInterface
290-
*/
291-
private function getMockedEventManager()
292-
{
293-
$mockBuilder = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
294-
->setMethods(['dispatch'])
295-
->disableOriginalConstructor();
296-
$mock = $mockBuilder->getMockForAbstractClass();
297-
298-
$mock->expects($this->any())
299-
->method('dispatch');
300-
301-
return $mock;
302-
}
303260
}

0 commit comments

Comments
 (0)