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:

Jason
  • 180
  • 11

1 Answers1

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;
};

});

bernieu2
  • 594
  • 3
  • 7