From 92e700fc08382a0c220eb035aab01dd3b039de9d Mon Sep 17 00:00:00 2001 From: "Hubert Van de Walle (huvw)" Date: Wed, 3 Aug 2022 18:25:01 +0000 Subject: [PATCH] [FIX] web: parseMonetary with NBSP as a thousands separator Steps to reproduce: - Switch odoo language to french - Create a client bill for Azure Interior of $1 000 000 - Confirm it - Go to the accounting dashboard - On the bank, click on reconcile - Select Azure interior - Click on the correct bill - Switch to Manual operations -> $1 000 000 is not a correct monetary field Cause of the issue: Recently in https://github.com/odoo/odoo/pull/94126 , `formatMonetary` switched from joining the currency and symbol from ` ` to a non breaking space, NBSP. To parse monetary values, the behavior was to split around NBSP to get the symbol on one side and the value on the other which is then passed to `parseFloat`. For the following examples, NBSP is replaced with an underscore. So `$_1000` becomes `$, 1000` But some languages such as french uses the same char as thousands separator. In that case, `$_1_000` becomes `$, 1, 000` and then the parse fails. opw-2937403 closes odoo/odoo#97513 X-original-commit: 9d36722797669498dfd1ad4659e5f29347ba30f3 Signed-off-by: Jorge Pinna Puissant (jpp) Signed-off-by: Hubert Van De Walle --- .../src/legacy/js/fields/field_utils.js | 22 +++++++++++-------- .../tests/legacy/fields/field_utils_tests.js | 14 +++++++++++- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/addons/web/static/src/legacy/js/fields/field_utils.js b/addons/web/static/src/legacy/js/fields/field_utils.js index aaec21709b9..547cc784125 100644 --- a/addons/web/static/src/legacy/js/fields/field_utils.js +++ b/addons/web/static/src/legacy/js/fields/field_utils.js @@ -616,16 +616,9 @@ function parseFloat(value) { * @throws {Error} if no float is found or if parameter does not respect monetary condition */ function parseMonetary(value, field, options) { - var values = value.split(' '); - if (values.length === 1) { - values = value.split(NBSP); - } - if (values.length === 1) { + if (!value.includes(NBSP) && !value.includes(' ')) { return parseFloat(value); } - else if (values.length !== 2) { - throw new Error(_.str.sprintf(core._t("'%s' is not a correct monetary field"), value)); - } options = options || {}; var currency = options.currency; if (!currency) { @@ -636,7 +629,18 @@ function parseMonetary(value, field, options) { } currency = session.get_currency(currency_id); } - return parseFloat(values[0] === currency.symbol ? values[1] : values[0]); + if (!value.includes(currency.symbol)) { + throw new Error(_.str.sprintf(core._t("'%s' is not a correct monetary field"), value)); + } + if (currency.position === 'before') { + return parseFloat(value + .replace(`${ currency.symbol }${ NBSP }`, '') + .replace(`${ currency.symbol } `, '')); + } else { + return parseFloat(value + .replace(`${ NBSP }${ currency.symbol }`, '') + .replace(` ${ currency.symbol }`, '')); + } } /** diff --git a/addons/web/static/tests/legacy/fields/field_utils_tests.js b/addons/web/static/tests/legacy/fields/field_utils_tests.js index 08c5281752f..d39ad635dbd 100644 --- a/addons/web/static/tests/legacy/fields/field_utils_tests.js +++ b/addons/web/static/tests/legacy/fields/field_utils_tests.js @@ -261,8 +261,9 @@ QUnit.test('parse integer', function(assert) { }); QUnit.test('parse monetary', function(assert) { - assert.expect(11); + assert.expect(13); var originalCurrencies = session.currencies; + const originalParameters = _.clone(core._t.database.parameters); session.currencies = { 1: { digits: [69, 2], @@ -288,7 +289,18 @@ QUnit.test('parse monetary', function(assert) { assert.throws(function() {fieldUtils.parse.monetary("$ 12.00", {}, {currency_id: 1})}, /is not a correct/); assert.throws(function() {fieldUtils.parse.monetary("$ 12.00 34", {}, {currency_id: 3})}, /is not a correct/); + // In some languages, the non-breaking space character is used as thousands separator. + const nbsp = '\u00a0'; + _.extend(core._t.database.parameters, { + grouping: [3, 0], + decimal_point: ',', + thousands_sep: nbsp, + }); + assert.strictEqual(fieldUtils.parse.monetary(`1${nbsp}000.00${nbsp}€`, {}, {currency_id: 1}), 1000); + assert.strictEqual(fieldUtils.parse.monetary(`$${nbsp}1${nbsp}000.00`, {}, {currency_id: 3}), 1000); + session.currencies = originalCurrencies; + core._t.database.parameters = originalParameters; }); QUnit.test('parse percentage', function(assert) {