Skip to content

magento/magento2#22856: Catalog price rules are not working with custom options as expected. #22917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jan 8, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

/**
* Product options abstract type block
*
* @author Magento Core Team <core@magentocommerce.com>
*/
declare(strict_types=1);

namespace Magento\Catalog\Block\Product\View\Options;

use Magento\Catalog\Pricing\Price\BasePrice;
use Magento\Catalog\Pricing\Price\CalculateCustomOptionCatalogRule;
use Magento\Catalog\Pricing\Price\CustomOptionPriceInterface;
use Magento\Framework\App\ObjectManager;

/**
* Product options section abstract block.
Expand Down Expand Up @@ -47,20 +45,29 @@ abstract class AbstractOptions extends \Magento\Framework\View\Element\Template
*/
protected $_catalogHelper;

/**
* @var CalculateCustomOptionCatalogRule
*/
private $calculateCustomOptionCatalogRule;

/**
* @param \Magento\Framework\View\Element\Template\Context $context
* @param \Magento\Framework\Pricing\Helper\Data $pricingHelper
* @param \Magento\Catalog\Helper\Data $catalogData
* @param array $data
* @param CalculateCustomOptionCatalogRule $calculateCustomOptionCatalogRule
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
\Magento\Framework\Pricing\Helper\Data $pricingHelper,
\Magento\Catalog\Helper\Data $catalogData,
array $data = []
array $data = [],
CalculateCustomOptionCatalogRule $calculateCustomOptionCatalogRule = null
) {
$this->pricingHelper = $pricingHelper;
$this->_catalogHelper = $catalogData;
$this->calculateCustomOptionCatalogRule = $calculateCustomOptionCatalogRule
?? ObjectManager::getInstance()->get(CalculateCustomOptionCatalogRule::class);
parent::__construct($context, $data);
}

Expand Down Expand Up @@ -161,6 +168,15 @@ protected function _formatPrice($value, $flag = true)
$priceStr = $sign;

$customOptionPrice = $this->getProduct()->getPriceInfo()->getPrice('custom_option_price');

if (!$value['is_percent']) {
$value['pricing_value'] = $this->calculateCustomOptionCatalogRule->execute(
$this->getProduct(),
(float)$value['pricing_value'],
(bool)$value['is_percent']
);
}

$context = [CustomOptionPriceInterface::CONFIGURATION_OPTION_FLAG => true];
$optionAmount = $customOptionPrice->getCustomAmount($value['pricing_value'], null, $context);
$priceStr .= $this->getLayout()->getBlock('product.price.render.default')->renderAmount(
Expand Down
123 changes: 43 additions & 80 deletions app/code/Magento/Catalog/Model/Product/Option.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Catalog\Model\Product;

Expand All @@ -16,8 +17,10 @@
use Magento\Catalog\Model\Product\Option\Type\File;
use Magento\Catalog\Model\Product\Option\Type\Select;
use Magento\Catalog\Model\Product\Option\Type\Text;
use Magento\Catalog\Model\Product\Option\Value;
use Magento\Catalog\Model\ResourceModel\Product\Option\Value\Collection;
use Magento\Catalog\Pricing\Price\BasePrice;
use Magento\Catalog\Pricing\Price\CalculateCustomOptionCatalogRule;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Model\AbstractExtensibleModel;
Expand Down Expand Up @@ -123,6 +126,11 @@ class Option extends AbstractExtensibleModel implements ProductCustomOptionInter
*/
private $customOptionValuesFactory;

/**
* @var CalculateCustomOptionCatalogRule
*/
private $calculateCustomOptionCatalogRule;

/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
Expand All @@ -138,6 +146,7 @@ class Option extends AbstractExtensibleModel implements ProductCustomOptionInter
* @param ProductCustomOptionValuesInterfaceFactory|null $customOptionValuesFactory
* @param array $optionGroups
* @param array $optionTypesToGroups
* @param CalculateCustomOptionCatalogRule $calculateCustomOptionCatalogRule
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
Expand All @@ -154,14 +163,17 @@ public function __construct(
array $data = [],
ProductCustomOptionValuesInterfaceFactory $customOptionValuesFactory = null,
array $optionGroups = [],
array $optionTypesToGroups = []
array $optionTypesToGroups = [],
CalculateCustomOptionCatalogRule $calculateCustomOptionCatalogRule = null
) {
$this->productOptionValue = $productOptionValue;
$this->optionTypeFactory = $optionFactory;
$this->string = $string;
$this->validatorPool = $validatorPool;
$this->customOptionValuesFactory = $customOptionValuesFactory ?:
\Magento\Framework\App\ObjectManager::getInstance()->get(ProductCustomOptionValuesInterfaceFactory::class);
ObjectManager::getInstance()->get(ProductCustomOptionValuesInterfaceFactory::class);
$this->calculateCustomOptionCatalogRule = $calculateCustomOptionCatalogRule ??
ObjectManager::getInstance()->get(CalculateCustomOptionCatalogRule::class);
$this->optionGroups = $optionGroups ?: [
self::OPTION_GROUP_DATE => Date::class,
self::OPTION_GROUP_FILE => File::class,
Expand Down Expand Up @@ -193,10 +205,7 @@ public function __construct(
}

/**
* Get resource instance
*
* @return \Magento\Framework\Model\ResourceModel\Db\AbstractDb
* @deprecated 101.1.0 because resource models should be used directly
* @inheritdoc
*/
protected function _getResource()
{
Expand Down Expand Up @@ -462,10 +471,12 @@ public function afterSave()
*/
public function getPrice($flag = false)
{
if ($flag && $this->getPriceType() == self::$typePercent) {
$basePrice = $this->getProduct()->getPriceInfo()->getPrice(BasePrice::PRICE_CODE)->getValue();
$price = $basePrice * ($this->_getData(self::KEY_PRICE) / 100);
return $price;
if ($flag) {
return $this->calculateCustomOptionCatalogRule->execute(
$this->getProduct(),
(float)$this->getData(self::KEY_PRICE),
$this->getPriceType() === Value::TYPE_PERCENT
);
}
return $this->_getData(self::KEY_PRICE);
}
Expand Down Expand Up @@ -559,9 +570,7 @@ public function getSearchableData($productId, $storeId)
}

/**
* Clearing object's data
*
* @return $this
* @inheritdoc
*/
protected function _clearData()
{
Expand All @@ -571,9 +580,7 @@ protected function _clearData()
}

/**
* Clearing cyclic references
*
* @return $this
* @inheritdoc
*/
protected function _clearReferences()
{
Expand All @@ -594,9 +601,7 @@ protected function _getValidationRulesBeforeSave()
}

/**
* Get product SKU
*
* @return string
* @inheritdoc
*/
public function getProductSku()
{
Expand All @@ -608,9 +613,7 @@ public function getProductSku()
}

/**
* Get option id
*
* @return int|null
* @inheritdoc
* @codeCoverageIgnoreStart
*/
public function getOptionId()
Expand All @@ -619,60 +622,47 @@ public function getOptionId()
}

/**
* Get option title
*
* @return string
* @inheritdoc
*/
public function getTitle()
{
return $this->_getData(self::KEY_TITLE);
}

/**
* Get option type
*
* @return string
* @inheritdoc
*/
public function getType()
{
return $this->_getData(self::KEY_TYPE);
}

/**
* Get sort order
*
* @return int
* @inheritdoc
*/
public function getSortOrder()
{
return $this->_getData(self::KEY_SORT_ORDER);
}

/**
* Get is require
*
* @return bool
* @SuppressWarnings(PHPMD.BooleanGetMethodName)
* @inheritdoc
*/
public function getIsRequire()
{
return $this->_getData(self::KEY_IS_REQUIRE);
}

/**
* Get price type
*
* @return string|null
* @inheritdoc
*/
public function getPriceType()
{
return $this->_getData(self::KEY_PRICE_TYPE);
}

/**
* Get Sku
*
* @return string|null
* @inheritdoc
*/
public function getSku()
{
Expand Down Expand Up @@ -720,98 +710,71 @@ public function getImageSizeY()
}

/**
* Set product SKU
*
* @param string $productSku
* @return $this
* @inheritdoc
*/
public function setProductSku($productSku)
{
return $this->setData(self::KEY_PRODUCT_SKU, $productSku);
}

/**
* Set option id
*
* @param int $optionId
* @return $this
* @inheritdoc
*/
public function setOptionId($optionId)
{
return $this->setData(self::KEY_OPTION_ID, $optionId);
}

/**
* Set option title
*
* @param string $title
* @return $this
* @inheritdoc
*/
public function setTitle($title)
{
return $this->setData(self::KEY_TITLE, $title);
}

/**
* Set option type
*
* @param string $type
* @return $this
* @inheritdoc
*/
public function setType($type)
{
return $this->setData(self::KEY_TYPE, $type);
}

/**
* Set sort order
*
* @param int $sortOrder
* @return $this
* @inheritdoc
*/
public function setSortOrder($sortOrder)
{
return $this->setData(self::KEY_SORT_ORDER, $sortOrder);
}

/**
* Set is require
*
* @param bool $isRequired
* @return $this
* @inheritdoc
*/
public function setIsRequire($isRequired)
{
return $this->setData(self::KEY_IS_REQUIRE, $isRequired);
}

/**
* Set price
*
* @param float $price
* @return $this
* @inheritdoc
*/
public function setPrice($price)
{
return $this->setData(self::KEY_PRICE, $price);
}

/**
* Set price type
*
* @param string $priceType
* @return $this
* @inheritdoc
*/
public function setPriceType($priceType)
{
return $this->setData(self::KEY_PRICE_TYPE, $priceType);
}

/**
* Set Sku
*
* @param string $sku
* @return $this
* @inheritdoc
*/
public function setSku($sku)
{
Expand Down Expand Up @@ -952,7 +915,7 @@ public function setExtensionAttributes(
private function getOptionRepository()
{
if (null === $this->optionRepository) {
$this->optionRepository = \Magento\Framework\App\ObjectManager::getInstance()
$this->optionRepository = ObjectManager::getInstance()
->get(\Magento\Catalog\Model\Product\Option\Repository::class);
}
return $this->optionRepository;
Expand All @@ -966,7 +929,7 @@ private function getOptionRepository()
private function getMetadataPool()
{
if (null === $this->metadataPool) {
$this->metadataPool = \Magento\Framework\App\ObjectManager::getInstance()
$this->metadataPool = ObjectManager::getInstance()
->get(\Magento\Framework\EntityManager\MetadataPool::class);
}
return $this->metadataPool;
Expand Down
Loading