0

I have a requirement where I want to show the annual product price for virtual products. I have created products but custom options and added pricing for individual options. I have also added 2 new price types (annual_final_price & annual_old_price). I can see the prices in PDP but when I change the option, the annual prices are not changing.

Basically, I need to render custom product prices in PDP and it should change when we select different product options. Please let me know, how I can achieve this.

The annual price is shown at the bottom as 224,40. enter image description here

1 Answer 1

2

I have achieved this by adding new price-type in module's di.xml file by using below code:

<virtualType name="Magento\Catalog\Pricing\Price\Pool">
    <arguments>
        <argument name="prices" xsi:type="array">
            <item name="annual_final_price" xsi:type="string">VendorName\ModuleName\Pricing\Price\AnnualFinalPrice</item>
            <item name="annual_old_price" xsi:type="string">VendorName\ModuleName\Pricing\Price\AnnualOldPrice</item>
        </argument>
    </arguments>
</virtualType>

By adding above code, new price-type is created and to get the new price-type values, you need to create price-type pricing file:

VendorName\ModuleName\Pricing\Price\AnnualFinalPrice.php

<?php
namespace VendorName\ModuleName\Pricing\Price;

use Magento\Catalog\Model\Product;
use Magento\Framework\Pricing\Price\AbstractPrice;

/**
 * Final price model
 */
class AnnualFinalPrice extends AbstractPrice
{
    /**
     * Price type final
     */
    const PRICE_CODE = 'annual_final_price';

    /**
     * @var BasePrice
     */
    private $basePrice;

    /**
     * Get Value
     *
     * @return float|bool
     */
    public function getValue()
    {
        $annualPrice = $this->getBasePrice()->getValue() * 12;
        return max(0, $annualPrice);
    }

    /**
     * Retrieve base price instance lazily
     *
     * @return BasePrice|\Magento\Framework\Pricing\Price\PriceInterface
     */
    protected function getBasePrice()
    {
        if (!$this->basePrice) {
            $this->basePrice = $this->priceInfo->getPrice(\Magento\Catalog\Pricing\Price\BasePrice::PRICE_CODE);
        }
        return $this->basePrice;
    }
}

After above code, its ready to show the annual price of the product. And display the price, add below code inside app/design/frontend/themeName/ChildTheme/Magento_Catalog/templates/product/price/final_price.phtml

<span class="service-annual-price">
        <?php
            $annualSP = $block->renderAmount($annualFinalPriceModel->getAmount(), [
                'price_id'          => $block->getPriceId('annual-final-price-' . $idSuffix),
                'price_type'        => 'annualFinalPrice',
                'include_container' => true,
                'schema' => $schema
            ]);

            $annualOP = $block->renderAmount($annualOldPriceModel->getAmount(), [
                'price_id'          => $block->getPriceId('annual-old-price-' . $idSuffix),
                'price_type'        => 'annualOldPrice',
                'include_container' => true,
                'skip_adjustments'  => true
            ]);
        ?>
        <?= __("%1 au lieu de %2", $annualSP, $annualOP);?>
    </span>

After above code, annual price is visible on frontend. And if you have simple product without custom options, then this code will be enough to show the annual price. But if you have a custom option, follow below code to change prices based on option selection.

Create a around plugin by using below code:

<type name="Magento\Catalog\Block\Product\View">
    <plugin disabled="false" name="add_annual_price_in_configs" sortOrder="10" type="VendorName\ModuleName\Plugin\Catalog\Block\Product\View" />
</type>

Plugin Code:

<?php
namespace VendorName\ModuleName\Plugin\Catalog\Block\Product;

use Magento\Framework\Json\EncoderInterface;
use Magento\Framework\Locale\FormatInterface;
use Magento\Framework\Event\ManagerInterface as EventManager;

class View
{

    /**
     * @var EncoderInterface
     */
    protected $_jsonEncoder;

    /**
     * @var FormatInterface
     */
    protected $_localeFormat;

    /**
     * @var EventManager
     */
    protected $eventManager;

    public function __construct(
        EncoderInterface $_jsonEncoder,
        FormatInterface $_localeFormat,
        EventManager $eventManager
    ) {
        $this->_jsonEncoder = $_jsonEncoder;
        $this->_localeFormat = $_localeFormat;
        $this->_eventManager = $eventManager;
    }
    
    public function aroundGetJsonConfig(\Magento\Catalog\Block\Product\View $subject, callable $proceed)
    {
        $product = $subject->getProduct();

        if (!$subject->hasOptions()) {
            $config = [
                'productId' => $product->getId(),
                'priceFormat' => $subject->_localeFormat->getPriceFormat()
            ];
            return $this->_jsonEncoder->encode($config);
        }

        $tierPrices = [];
        $priceInfo = $product->getPriceInfo();
        $tierPricesList = $priceInfo->getPrice('tier_price')->getTierPriceList();
        foreach ($tierPricesList as $tierPrice) {
            $tierPrices[] = $tierPrice['price']->getValue() * 1;
        }
        $config = [
            'productId'   => (int)$product->getId(),
            'priceFormat' => $this->_localeFormat->getPriceFormat(),
            'prices'      => [
                'baseOldPrice' => [
                    'amount'      => $priceInfo->getPrice('regular_price')->getAmount()->getBaseAmount() * 1,
                    'adjustments' => []
                ],
                'oldPrice'   => [
                    'amount'      => $priceInfo->getPrice('regular_price')->getAmount()->getValue() * 1,
                    'adjustments' => []
                ],
                'basePrice'  => [
                    'amount'      => $priceInfo->getPrice('final_price')->getAmount()->getBaseAmount() * 1,
                    'adjustments' => []
                ],
                'finalPrice' => [
                    'amount'      => $priceInfo->getPrice('final_price')->getAmount()->getValue() * 1,
                    'adjustments' => []
                ],
                'annualFinalPrice' => [
                    'amount' => $priceInfo->getPrice('final_price')->getAmount()->getValue() * 12,
                    'adjustments' => []
                ],
                'annualOldPrice' => [
                    'amount' => $priceInfo->getPrice('regular_price')->getAmount()->getValue() * 12,
                    'adjustments' => []
                ]
            ],
            'idSuffix'    => '_clone',
            'tierPrices'  => $tierPrices
        ];

        $responseObject = new \Magento\Framework\DataObject();
        $this->_eventManager->dispatch('catalog_product_view_config', ['response_object' => $responseObject]);
        if (is_array($responseObject->getAdditionalOptions())) {
            foreach ($responseObject->getAdditionalOptions() as $option => $value) {
                $config[$option] = $value;
            }
        }

        return $this->_jsonEncoder->encode($config);
    }
}

Create a preference to pass annual prices for individual options.

<preference for="Magento\Catalog\Block\Product\View\Options" type="VendorName\ModuleName\Block\Product\View\Options" />

Create a php file:

<?php
namespace VendorName\ModuleName\Block\Product\View;

use Magento\Catalog\Model\Product\Option\Value;

class Options extends \Magento\Catalog\Block\Product\View\Options
{
    protected $pricingHelper;

    protected $_catalogData;

    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magento\Framework\Pricing\Helper\Data $pricingHelper,
        \Magento\Catalog\Helper\Data $catalogData,
        \Magento\Framework\Json\EncoderInterface $jsonEncoder,
        \Magento\Catalog\Model\Product\Option $option,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Stdlib\ArrayUtils $arrayUtils,
        array $data = []
    ) {
        $this->pricingHelper = $pricingHelper;
        $this->_catalogData = $catalogData;
        parent::__construct($context, $pricingHelper, $catalogData, $jsonEncoder, $option, $registry, $arrayUtils, $data);
    }

    /**
     * Get price configuration
     *
     * @param \Magento\Catalog\Model\Product\Option\Value|\Magento\Catalog\Model\Product\Option $option
     * @return array
     */
    protected function _getPriceConfiguration($option)
    {
        $optionPrice = $option->getPrice(true);
        if ($option->getPriceType() !== Value::TYPE_PERCENT) {
            $optionPrice = $this->pricingHelper->currency($optionPrice, false, false);
        }
        $data = [
            'prices' => [
                'oldPrice' => [
                    'amount' => $this->pricingHelper->currency($option->getRegularPrice(), false, false),
                    'adjustments' => [],
                ],
                'basePrice' => [
                    'amount' => $this->_catalogData->getTaxPrice(
                        $option->getProduct(),
                        $optionPrice,
                        false,
                        null,
                        null,
                        null,
                        null,
                        null,
                        false
                    ),
                ],
                'finalPrice' => [
                    'amount' => $this->_catalogData->getTaxPrice(
                        $option->getProduct(),
                        $optionPrice,
                        true,
                        null,
                        null,
                        null,
                        null,
                        null,
                        false
                    ),
                ],
                'annualFinalPrice' => [
                    'amount' => $optionPrice * 12
                ],
                'annualOldPrice' => [
                    'amount' => $this->pricingHelper->currency($option->getRegularPrice(), false, false) * 12,
                ]
            ],
            'type' => $option->getPriceType(),
            'name' => $option->getTitle(),
        ];
        return $data;
    }
}

NOTE: This code is used just to display the annual price of the product. It does not change product price in cart.

1
  • thank you for posting this
    – Robert
    Commented Apr 14 at 17:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.