Magento 2 Product Price – Changing Display to Show 4 Decimal Places

magento2price

My company is using an extension to create a custom product which is unique in that the pricing goes out 4 decimal places. There was a whole lot that went into this prior to me getting involved, but all this is in place already and working.

The problem I'm dealing with today is that the price is automatically rounding on the front end, and I want to change it so that it shows the pricing with all 4 decimal places so that people know the actual price of the item when viewing the product.

Here is my plan to do this:

  1. Extend the class Magento\Framework\Pricing\Render\Amount and add a function that will output the price with 4 decimal places, without effecting any other functionality.
  2. Create a new template that uses the new class, and keep it the same except the price display, which will use the new function to display the full price.
  3. Use xml file to replace the default price display with this template

Is this the correct way to do this? I don't expect a full tutorial, of course, so I just want to know if I'm at least at a good starting point… although any other helpful advice would be appreciated.

Running Magento 2.1.2

Best Answer

From what I found the pricing precision is defined by Magento\Framework\Pricing\PriceCurrencyInterface::DEFAULT_PRECISION and I didn't see any implementing classes that changes this. I was able to accomplish this with of plugins. This should point you down the right path on the backend. The increased precision is visible on the frontend, but on product view pages price-utils.js formats the price after the page loads and changes the precision back to two even after the Magento\Framework\Locale\Format plugin updates the frontend precision configurations.

I believe this is caused by this line in Magento/Catalog/view/base/web/js/price-utils.js around line 73

(precision ? decimalSymbol + am.toFixed(2).replace(/-/, 0).slice(2) : '');

I wound up overriding this file in the module and changing the line to

(precision ? decimalSymbol + am.toFixed(precision).replace(/-/, 0).slice(2) : '');

I'm sure there is a better way to do that, but I had to move on. The code for the plugins is below:

Vendor/Module/etc/di.xml

<?xml version="1.0"?>
<config>
  <type name="Magento\Framework\Pricing\Render\Amount">
    <plugin name="vendor_module_framework_pricing_render_amount" type="Vendor\Module\Plugin\Framework\Pricing\Render\Amount" />
  </type>
  <type name="Magento\Directory\Model\PriceCurrency">
    <plugin name="vendor_module_directory_model_pricecurrency" type="Vendor\Module\Plugin\Directory\Model\PriceCurrency" />
  </type>
  <type name="Magento\Framework\Locale\Format">
    <plugin name="vendor_module_framework_locale_format" type="Vendor\Module\Plugin\Framework\Locale\Format" />
  </type>
</config>

Vendor/Module/Plugin/Framework/Pricing/Render/Amount.php

<?php
namespace Vendor\Module\Plugin\Framework\Pricing\Render;

use Magento\Framework\Pricing\PriceCurrencyInterface;

class Amount
{
  public function beforeFormatCurrency(
    $subject,
    $amount,
    $includeContainer = true,
    $precision = PriceCurrencyInterface::DEFAULT_PRECISION
  ) {
    return [$amount, $includeContainer, 4];
  }
}

Vendor/Module/Plugin/Directory/Model/PriceCurrency.php

<?php
namespace Vendor\Module\Plugin\Directory\Model;

class PriceCurrency
{
  public function beforeConvertAndRound(
    $subject,
    $amount,
    $scope = null,
    $currency = null,
    $precision = \Magento\Directory\Model\PriceCurrency::DEFAULT_PRECISION
  ) {
    return [$amount, $scope, $currency, 4];
  }

  public function beforeFormat(
    $subject,
    $amount,
    $includeContainer = true,
    $precision = \Magento\Directory\Model\PriceCurrency::DEFAULT_PRECISION,
    $scope = null,
    $currency = null
  ) {
    return [$amount, $includeContainer, 4, $scope, $currency];
  }
}

Vendor/Module/Plugin/Framework/Locale/Format.php

<?php
namespace Vendor\Module\Plugin\Framework\Locale;

class Format
{
  public function afterGetPriceFormat($subject, $result) {
    $result['precision'] = 4;
    $result['requiredPrecision'] = 4;

    return $result;
  }
}
Related Topic