diff --git a/addons/web/static/src/views/fields/parsers.js b/addons/web/static/src/views/fields/parsers.js index 9655b0c31b5..8f4187fa8c1 100644 --- a/addons/web/static/src/views/fields/parsers.js +++ b/addons/web/static/src/views/fields/parsers.js @@ -159,20 +159,26 @@ export function parsePercentage(value) { /** * Try to extract a monetary value from a string. The localization is considered in the process. - * This is a very lenient function such that it just strips non-numeric characters at the - * beginning and end of the string, and then tries to parse the remaining string as a float. + * This is a very lenient function such that it ignores everything before we encounter a substring consisting of either + * - a sign (- or +) + * - an equals sign (signaling the start of a mathematical expression) + * - a decimal point + * - a number + * We then remove any non-numeric characters at the end + * * * @param {string} value * @returns {number} */ export function parseMonetary(value) { value = value.trim(); - const regex = new RegExp(`^[^\\d\\-+=]*(?.*?)[^\\d]*$`); - const match = value.match(regex); - if (!match) { - throw new InvalidNumberError(`"${value}" is not a valid number.`); + const startMatch = value.match( + new RegExp(`[\\d\\-+=]|${escapeRegExp(localization.decimalPoint)}`) + ); + if (startMatch) { + value = value.substring(startMatch.index); } - value = match.groups.strToParse; + value = value.replace(/\D*$/, ""); return parseFloat(value); } diff --git a/addons/web/static/tests/views/fields/parsers_tests.js b/addons/web/static/tests/views/fields/parsers_tests.js index d1a3036643a..6964b062536 100644 --- a/addons/web/static/tests/views/fields/parsers_tests.js +++ b/addons/web/static/tests/views/fields/parsers_tests.js @@ -129,6 +129,7 @@ QUnit.module("Fields", (hooks) => { assert.strictEqual(parseMonetary("100.00\u00a0€"), 100); assert.strictEqual(parseMonetary("-100.00"), -100); assert.strictEqual(parseMonetary("1,000.00"), 1000); + assert.strictEqual(parseMonetary(".1"), 0.1); assert.strictEqual(parseMonetary("1,000,000.00"), 1000000); assert.strictEqual(parseMonetary("$\u00a0125.00"), 125); assert.strictEqual(parseMonetary("1,000.00\u00a0€"), 1000); @@ -165,6 +166,30 @@ QUnit.module("Fields", (hooks) => { assert.strictEqual(parseMonetary("1\u00a0000,14DOLLARS"), 1000.14); assert.strictEqual(parseMonetary("DOLLARS+1\u00a0000,15"), 1000.15); assert.strictEqual(parseMonetary("EURO-1\u00a0000,16DOGE"), -1000.16); + + // comma as decimal point and dot as thousands separator + patchWithCleanup(localization, { thousandsSep: ".", decimalPoint: "," }); + assert.strictEqual(parseMonetary("10,08"), 10.08); + assert.strictEqual(parseMonetary(""), 0); + assert.strictEqual(parseMonetary("0"), 0); + assert.strictEqual(parseMonetary("100,12\u00a0€"), 100.12); + assert.strictEqual(parseMonetary("-100,12"), -100.12); + assert.strictEqual(parseMonetary("1.000,12"), 1000.12); + assert.strictEqual(parseMonetary(",1"), 0.1); + assert.strictEqual(parseMonetary("1.000.000,12"), 1000000.12); + assert.strictEqual(parseMonetary("$\u00a0125,12"), 125.12); + assert.strictEqual(parseMonetary("1.000,00\u00a0€"), 1000); + assert.strictEqual(parseMonetary(","), 0); + assert.strictEqual(parseMonetary("1\u00a0"), 1); + assert.strictEqual(parseMonetary("\u00a01"), 1); + assert.strictEqual(parseMonetary("12,34 €"), 12.34); + assert.strictEqual(parseMonetary("$ 12,34"), 12.34); + + // Can evaluate expression + assert.strictEqual(parseMonetary("=1.000,1 + 2.000,2"), 3000.3); + assert.strictEqual(parseMonetary("=1.000,00 + 11.121,00"), 12121); + assert.strictEqual(parseMonetary("=1000,00 + 11122,00"), 12122); + assert.strictEqual(parseMonetary("=1000 + 11123"), 12123); }); QUnit.test("parsers fallback on english localisation", function (assert) {