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.