[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
This commit is contained in:
Joseph Caburnay
2022-12-13 17:03:25 +01:00
parent 2e497b886e
commit 89c6124599
2 changed files with 11 additions and 5 deletions
@@ -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);
@@ -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);
});