1

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

2 Answers 2

12

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;
  }
}
7
  • Thanks for all the time you put into this. I'll try using your advice today and see how it works. Just to be clear this is only going to affect the display of the price on the frontend? We had major issues with our pricing being 4 decimal before, caused by the fact that paypal (and likely other merchants) will round it automatically, causing a mismatch. I don't want to open up those problems again.
    – jamil
    Dec 19, 2016 at 16:28
  • You'll definitely want to test with payment integrations. I didn't see any references to these functions withing the core payment methods, but I did not test this. I did notice the precision on the frontend for the cart item and checkout totals does increase to 4 though the last two digits are always 00. This is likely from the price being dropped to a precision of 2 when adding the item to the cart. This may not be the case on your install though given the previous modifications had increased the precision far enough into the checkout process to break Paypal.
    – Pmclain
    Dec 19, 2016 at 17:09
  • After a lot of head bashing into desk I got the results I wanted! I have yet to test live to see if it will play nicely with actual transactions; however you have more than thoroughly answered my question so I marked it as such. Thank you random magento hero!
    – jamil
    Dec 20, 2016 at 0:03
  • I am using Magento 2.1.5. I tried the solution, it working on home page but when enter any category page I got this error ` Uncaught Error: Undefined class constant 'self::DEFAULT_PRECISION' in /var/www/html/magento2/app/code/Vendor/Module/Plugin/Directory/Model/PriceCurrency.php:16 `
    – Jsparo30
    May 1, 2017 at 11:34
  • I updated the answer changing self::DEFAULT_PRECISION, which didn't exists, to \Magento\Directory\Model\PriceCurrency::DEFAULT_PRECISION
    – Pmclain
    May 1, 2017 at 16:34
0

The module written above is doing the trick. I've installed it and changed the precision in the price-utils.js file. I'm getting accurate 4 decimal placed prices (tier prices included) on the product detail page. However, I'm having the same issue as Pmclain where I get 4 decimal places in the cart, but the last 2 are always zero. Any ideas on how to fix this?

2
  • Also, is there a way that the 4 decimal places can be preserved in the Magento admin? I can add a product with a price of 0.3525. When the screen refreshes, it says 0.4 for the price. The database does indeed have the 0.3525 price and it's reflected on the frontend accurately. May 23, 2017 at 13:11
  • Hi @Michaek Zenner Did you find any solution here ?
    – skm
    Jun 30, 2020 at 5:48

Your Answer

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

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