[FIX] web: parseMonetary of decimal value without leading 0

Steps to reproduce
==================

- Open a product form view
- Enter .5 in the Cost field

It is parsed as 5 but it should be 0.5

Cause of the issue
==================

When trying to strip the currency symbol from the input, the leading
decimal separator was also removed

Solution
========

The decimalPoint can have multiple characters.
This means that we can't simply add the decimal separator inside the negated
character class.

Instead, what we can do is skip everything until we find a interesting
substring. (more details in the comment)

We then remove everything that is not a digit at the end.

Finally, we can pass that to `parseFloat`

closes odoo/odoo#123358

X-original-commit: fa466d75da3b30ac1e512a95436075ef1461a95c
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
Signed-off-by: Hubert Van De Walle <huvw@odoo.com>
This commit is contained in:
Hubert Van de Walle (huvw)
2023-06-02 12:04:13 +02:00
parent 78b674d8d4
commit ea8e42cdba
2 changed files with 38 additions and 7 deletions
+13 -7
View File
@@ -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\\-+=]*(?<strToParse>.*?)[^\\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);
}
@@ -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) {