Skip to content
This repository was archived by the owner on Apr 29, 2019. It is now read-only.

Commit b62df9f

Browse files
committed
MAGETWO-72875: Incorrect catalog rule price for bundle product with custom option
1 parent d76b6c1 commit b62df9f

File tree

19 files changed

+305
-120
lines changed

19 files changed

+305
-120
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: 19 additions & 14 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,
@@ -177,7 +190,7 @@ public function setProduct($product)
177190
*/
178191
public function getProduct()
179192
{
180-
if ($this->_product === null) {
193+
if (is_null($this->_product)) {
181194
$this->_product = $this->getOption()->getProduct();
182195
}
183196
return $this->_product;
@@ -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: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
return $price;
41+
}
42+
return $optionValue->getData(ProductOptionValue::KEY_PRICE);
43+
}
44+
}

0 commit comments

Comments
 (0)