From 89c6124599458366da2cb7f9700003130ebab1a3 Mon Sep 17 00:00:00 2001 From: Joseph Caburnay Date: Wed, 30 Nov 2022 08:47:21 +0000 Subject: [PATCH] [FIX] web: properly parse expression **Issue:** - Set the decimal point to "," and the thousand separator to ".". - In a float or monetary field, enter "=1.000,1+2.000,2" - BUG: It's evaluated to: 30003 **Solution:** Problematic evaluation steps: ``` -> parseNumber("=1.000,1+2.000,2") - thousands separator are removed and decimals are converted to "." so the string becomes "=1000.1+2000.2". -> parseNumber("1000.1") + parseNumber("2000.1") - since "." is the thousands separator, it will be removed (replaced by empty string) -> 10001 + 20001 -> 30003 ``` Because the main parser `parseNumber` is recursive in nature, we need to make sure that the logic that removes the thousands separator and replaces the decimal point to "." is not called in the branch that evaluates an input expression. With this change, the new evaluation steps are: ``` -> parseNumber("=1.000,1+2.000,2") -> parseNumber("1.000,1") + parseNumber("2.000,1") -> 1000.1 + 2000.1 -> 3000.3 ``` X-original-commit: 91eb5c40ce898428fb15d945d70510b92e9ebb03 Part-of: odoo/odoo#107862 --- addons/web/static/src/views/fields/parsers.js | 10 +++++----- addons/web/static/tests/views/fields/parsers_tests.js | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/addons/web/static/src/views/fields/parsers.js b/addons/web/static/src/views/fields/parsers.js index 6a5eadbbf38..ec986f66535 100644 --- a/addons/web/static/src/views/fields/parsers.js +++ b/addons/web/static/src/views/fields/parsers.js @@ -38,16 +38,16 @@ function evaluateMathematicalExpression(expr, context = {}) { * @returns {number} */ function parseNumber(value, options = {}) { - // a number can have the thousand separator multiple times. ex: 1,000,000.00 - value = value.replaceAll(new RegExp(escapeRegExp(options.thousandsSep), "g") || ",", ""); - // a number only have one decimal separator - value = value.replace(new RegExp(escapeRegExp(options.decimalPoint), "g") || ".", "."); - if (value.startsWith("=")) { value = evaluateMathematicalExpression(value.substring(1)); if (options.truncate) { value = Math.trunc(value); } + } else { + // a number can have the thousand separator multiple times. ex: 1,000,000.00 + value = value.replaceAll(new RegExp(escapeRegExp(options.thousandsSep), "g") || ",", ""); + // a number only have one decimal separator + value = value.replace(new RegExp(escapeRegExp(options.decimalPoint), "g") || ".", "."); } return Number(value); diff --git a/addons/web/static/tests/views/fields/parsers_tests.js b/addons/web/static/tests/views/fields/parsers_tests.js index 95710685404..ba1c2487c52 100644 --- a/addons/web/static/tests/views/fields/parsers_tests.js +++ b/addons/web/static/tests/views/fields/parsers_tests.js @@ -40,6 +40,12 @@ QUnit.module("Fields", (hooks) => { patchWithCleanup(localization, { decimalPoint: ",", thousandsSep: "." }); assert.strictEqual(parseFloat("1.234,567"), 1234.567); + // Can evaluate expression from locale with decimal point different from ".". + assert.strictEqual(parseFloat("=1.000,1 + 2.000,2"), 3000.3); + assert.strictEqual(parseFloat("=1.000,00 + 11.121,00"), 12121); + assert.strictEqual(parseFloat("=1000,00 + 11122,00"), 12122); + assert.strictEqual(parseFloat("=1000 + 11123"), 12123); + patchWithCleanup(localization, { decimalPoint: ",", thousandsSep: false }); assert.strictEqual(parseFloat("1234,567"), 1234.567); });