[FIX] web: formatter: monetary with human number
HumanNumber now correctly rounds the number according to decimals (bug with value < 1000 eg: 0.02) It also correctly keeps `decimals` significant figures whatever powers of 10^3 it should keep The monetary formatter now passes the currency's digits to human number Part-of: odoo/odoo#73311
This commit is contained in:
committed by
Aaron Bohy
parent
0008067ee5
commit
a19ad0fe24
@@ -36,7 +36,9 @@ function insertThousandsSep(number, thousandsSep = ",", grouping = [3, 0]) {
|
||||
* @private
|
||||
* @param {number} number to format
|
||||
* @param {Object} [options] Options to format
|
||||
* @param {number} [options.decimals=0] maximum number of decimals to use
|
||||
* @param {number} [options.decimals=0] number of decimals to use
|
||||
* if minDigits > 1 is used and effective on the number then decimals
|
||||
* will be shrunk to zero, to avoid displaying irrelevant figures ( 0.01 compared to 1000 )
|
||||
* @param {number} [options.minDigits=1]
|
||||
* the minimum number of digits to preserve when switching to another
|
||||
* level of thousands (e.g. with a value of '2', 4321 will still be
|
||||
@@ -44,11 +46,11 @@ function insertThousandsSep(number, thousandsSep = ",", grouping = [3, 0]) {
|
||||
* @returns {string}
|
||||
*/
|
||||
function humanNumber(number, options = { decimals: 0, minDigits: 1 }) {
|
||||
number = Math.round(number);
|
||||
const decimals = options.decimals || 0;
|
||||
const minDigits = options.minDigits || 1;
|
||||
const d2 = Math.pow(10, decimals);
|
||||
const numberMagnitude = +number.toExponential().split("e+")[1];
|
||||
number = Math.round(number * d2) / d2;
|
||||
// the case numberMagnitude >= 21 corresponds to a number
|
||||
// better expressed in the scientific format.
|
||||
if (numberMagnitude >= 21) {
|
||||
@@ -72,7 +74,10 @@ function humanNumber(number, options = { decimals: 0, minDigits: 1 }) {
|
||||
}
|
||||
}
|
||||
const { decimalPoint, grouping, thousandsSep } = l10n;
|
||||
const [integerPart, decimalPart] = String(number).split(".");
|
||||
|
||||
// determine if we should keep the decimals (we don't want to display 1,020.02k for 1020020)
|
||||
const decimalsToKeep = number >= 1000 ? 0 : decimals;
|
||||
const [integerPart, decimalPart] = number.toFixed(decimalsToKeep).split(".");
|
||||
const int = insertThousandsSep(sign * Number(integerPart), thousandsSep, grouping);
|
||||
if (!decimalPart) {
|
||||
return int + symbol;
|
||||
@@ -282,7 +287,13 @@ export function formatMonetary(value, options = {}) {
|
||||
const currency = session.currencies[currencyId];
|
||||
const digits = (currency && currency.digits) || options.digits;
|
||||
|
||||
const formatted = options.humanReadable ? humanNumber(value) : formatFloat(value, { digits });
|
||||
let formatted;
|
||||
if (options.humanReadable) {
|
||||
formatted = humanNumber(value, { decimals: digits ? digits[1] : 2 });
|
||||
} else {
|
||||
formatted = formatFloat(value, { digits });
|
||||
}
|
||||
|
||||
if (!currency || options.noSymbol) {
|
||||
return formatted;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(10200000, { humanReadable: true, decimals: 2, minDigits: 2 }),
|
||||
"10.2M"
|
||||
"10.20M"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(1020, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
@@ -69,15 +69,15 @@ QUnit.module("Fields", (hooks) => {
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(1002, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
"1k"
|
||||
"1.00k"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(101, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
"101"
|
||||
"101.00"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(64.2, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
"64"
|
||||
"64.20"
|
||||
);
|
||||
assert.strictEqual(formatFloat(1e18, { humanReadable: true }), "1E");
|
||||
assert.strictEqual(
|
||||
@@ -110,7 +110,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(-10200000, { humanReadable: true, decimals: 2, minDigits: 2 }),
|
||||
"-10.2M"
|
||||
"-10.20M"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(-1020, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
@@ -118,15 +118,15 @@ QUnit.module("Fields", (hooks) => {
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(-1002, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
"-1k"
|
||||
"-1.00k"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(-101, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
"-101"
|
||||
"-101.00"
|
||||
);
|
||||
assert.strictEqual(
|
||||
formatFloat(-64.2, { humanReadable: true, decimals: 2, minDigits: 1 }),
|
||||
"-64"
|
||||
"-64.20"
|
||||
);
|
||||
assert.strictEqual(formatFloat(-1e18, { humanReadable: true }), "-1E");
|
||||
assert.strictEqual(
|
||||
@@ -235,9 +235,14 @@ QUnit.module("Fields", (hooks) => {
|
||||
formatMonetary(1234567.654, { currencyId: 10, noSymbol: true }),
|
||||
"1,234,567.65"
|
||||
);
|
||||
assert.deepEqual(formatMonetary(8.0, { currencyId: 10, humanReadable: true }), "8.00 €");
|
||||
assert.deepEqual(
|
||||
formatMonetary(1234567.654, { currencyId: 10, humanReadable: true }),
|
||||
"1M €"
|
||||
"1.23M €"
|
||||
);
|
||||
assert.deepEqual(
|
||||
formatMonetary(1990000.001, { currencyId: 10, humanReadable: true }),
|
||||
"1.99M €"
|
||||
);
|
||||
assert.deepEqual(
|
||||
formatMonetary(1234567.654, { currencyId: 44, digits: [69, 1] }),
|
||||
@@ -269,6 +274,17 @@ QUnit.module("Fields", (hooks) => {
|
||||
assert.strictEqual(formatMonetary(200, { field: floatField, data }), "$ 200.00");
|
||||
});
|
||||
|
||||
QUnit.test("formatMonetary without currency", function (assert) {
|
||||
patchWithCleanup(session, {
|
||||
currencies: {},
|
||||
});
|
||||
assert.deepEqual(
|
||||
formatMonetary(1234567.654, { currencyId: 10, humanReadable: true }),
|
||||
"1.23M"
|
||||
);
|
||||
assert.deepEqual(formatMonetary(1234567.654, { currencyId: 10 }), "1,234,567.65");
|
||||
});
|
||||
|
||||
QUnit.test("formatPercentage", function (assert) {
|
||||
assert.strictEqual(formatPercentage(false), "0%");
|
||||
assert.strictEqual(formatPercentage(0), "0%");
|
||||
|
||||
Reference in New Issue
Block a user