0

I need a solution to strip decimals, but only from the prices that have ,00 decimals.

Example 1:
Price currently showing: € 543,00
Price should show: €543

Example 2:
Price currently showing: €280,95
Price should show: €280,95 (which is good)

I've tried multiple Price Formatting extensions, but none seem to do what I want. They're hiding all decimals, some even do this by rounding the price. That is not what I need. Does anybody know a working solution? I've been looking for weeks, but can't seem to find a solution.

The solution needs to cover at least category pages and product pages.

Same questions, but accepted solutions are wrong:

1 Answer 1

1

Take a look at following files:

vendor/magento/module-catalog/view/base/web/js/price-utils.js (controls the price rendering on product view pages)

vendor/magento/framework/Pricing/Render/Amount.php (controls rendering of blocks throughout)

In the Amount.php file you'll find this function:

public function formatCurrency(
    $amount,
    $includeContainer = true,
    $precision = PriceCurrencyInterface::DEFAULT_PRECISION
) {
    return $this->priceCurrency->format($amount, $includeContainer, $precision);
}

We need to write a plugin to override this function:

  1. your custom module etc/di.xml

enter image description here

  1. Vendor\Module\Pricing\Amount.php

     /**
      * @param PriceCurrencyInterface $priceCurrency
      */
     public function __construct(
         \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
     ) {
         $this->priceCurrency = $priceCurrency;
     }
    
     /**
      * Format price value
      *
      * @param float $amount
      * @param bool $includeContainer
      * @param int $precision
      * @return float
      */
     public function afterFormatCurrency(\Magento\Framework\Pricing\Render\Amount $subject, $result)
     {
       $amount = $subject->getAmount()->getValue();
       $includeContainer = true;
       $precision = null;
         if (floor($amount) == $amount) {
           return $this->priceCurrency->format($amount, $includeContainer, $precision = 0);
         }
         return $result;
     }
    

This should change price block output throughout (category, related, etc).

But, back to the first file - this will change the product view page back to a format with .00, so we also need to update this file too.

In function formatPrice of price-utils.js you will find below line

precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;

Update this to

if (Number.isInteger(amount)) {
  precision = 0;
} else {
  precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;
}

We can make this change using mixin. view/frontend/requirejs-config.js

config: {
        mixins: {
          'Magento_Catalog/js/price-utils': {
                'Vendor_Module/js/price-utils': true
          }
    }
}

view/frontend/web/js/price-utils.js

    define([
    'jquery',
    'underscore'
   ],
    function ($, _) {
        'use strict';

        var globalPriceFormat = {
            requiredPrecision: 2,
            integerRequired: 1,
            decimalSymbol: ',',
            groupSymbol: ',',
            groupLength: ','
        };

        return function (target) {

          function stringPad(string, times) {
              return (new Array(times + 1)).join(string);
          }

            target.formatPrice = function formatPrice(amount, format, isShowSign) {
              var s = '',
                  precision, integerRequired, decimalSymbol, groupSymbol, groupLength, pattern, i, pad, j, re, r, am;

              format = _.extend(globalPriceFormat, format);

              // copied from price-option.js | Could be refactored with varien/js.js
              if (Number.isInteger(amount)) {
                precision = 0;
              } else {
                precision = isNaN(format.requiredPrecision = Math.abs(format.requiredPrecision)) ? 2 : format.requiredPrecision;
              }

              integerRequired = isNaN(format.integerRequired = Math.abs(format.integerRequired)) ? 1 : format.integerRequired;
              decimalSymbol = format.decimalSymbol === undefined ? ',' : format.decimalSymbol;
              groupSymbol = format.groupSymbol === undefined ? '.' : format.groupSymbol;
              groupLength = format.groupLength === undefined ? 3 : format.groupLength;
              pattern = format.pattern || '%s';

              if (isShowSign === undefined || isShowSign === true) {
                  s = amount < 0 ? '-' : isShowSign ? '+' : '';
              } else if (isShowSign === false) {
                  s = '';
              }
              pattern = pattern.indexOf('{sign}') < 0 ? s + pattern : pattern.replace('{sign}', s);

              // we're avoiding the usage of to fixed, and using round instead with the e representation to address
              // numbers like 1.005 = 1.01. Using ToFixed to only provide trailing zeroes in case we have a whole number
              i = parseInt(
                      amount = Number(Math.round(Math.abs(+amount || 0) + 'e+' + precision) + ('e-' + precision)),
                      10
                  ) + '';
              pad = i.length < integerRequired ? integerRequired - i.length : 0;

              i = stringPad('0', pad) + i;

              j = i.length > groupLength ? i.length % groupLength : 0;
              re = new RegExp('(\\d{' + groupLength + '})(?=\\d)', 'g');

              // replace(/-/, 0) is only for fixing Safari bug which appears
              // when Math.abs(0).toFixed() executed on '0' number.
              // Result is '0.-0' :(

              am = Number(Math.round(Math.abs(amount - i) + 'e+' + precision) + ('e-' + precision));
              r = (j ? i.substr(0, j) + groupSymbol : '') +
                  i.substr(j).replace(re, '$1' + groupSymbol) +
                  (precision ? decimalSymbol + am.toFixed(precision).replace(/-/, 0).slice(2) : '');

              return pattern.replace('%s', r).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
            };

            return target;
    };
});
3
  • Thank you for the clear information. I'll give this a try tomorrow or the day after, and let you know!
    – Jason
    Mar 23, 2021 at 17:36
  • 1
    I updated my answer as you should use plugin method to override the function.
    – bernieu2
    Mar 25, 2021 at 4:16
  • Thanks a lot, exactly the information I needed!
    – Jason
    Mar 29, 2021 at 8:57

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.