diff --git a/addons/web/static/src/core/l10n/currency.js b/addons/web/static/src/core/l10n/currency.js index bcee0f39854..598bd5c297d 100644 --- a/addons/web/static/src/core/l10n/currency.js +++ b/addons/web/static/src/core/l10n/currency.js @@ -1,6 +1,6 @@ /** @odoo-module **/ -import { formatFloat, humanNumber } from "./numbers"; +import { formatFloat, humanNumber, parseFloat, InvalidNumberError } from "./numbers"; /** * Formats a value as a currency. @@ -36,3 +36,37 @@ export function formatCurrency(value, cid, options = {}) { return `${currency.symbol} ${formatted}`; } } + +/** + * Try to extract a monetary value from a string. The localization is considered in the process. + * The monetary value can have the formats sym$ float, float$ sym or float + * where $  is a non breaking space and sym is a currency symbol. + * If a symbol is found it must correspond to the default currency symbol or to the + * symbol of the currency whose id is passed in options. + * + * @param {string} value + * @param {Object} [options={}] + * @param {number} [options.currencyId] + * @returns {number} float + */ + export function parseCurrency(value, options = {}) { + let values = value.split(" "); + if (values.length === 1) { + return parseFloat(value); + } + let currency; + if (options.currencyId) { + currency = odoo.session_info.currencies[options.currencyId]; + } else { + currency = Object.values(odoo.session_info.currencies)[0]; + } + const symbolIndex = values.findIndex((v) => v === currency.symbol); + if (symbolIndex === -1) { + throw new InvalidNumberError(`"${value}" is not a correct number`); + } + values.splice(symbolIndex, 1); + if (values.length !== 1) { + throw new InvalidNumberError(`"${value}" is not a correct number`); + } + return parseFloat(values[0]); +} diff --git a/addons/web/static/src/core/l10n/numbers.js b/addons/web/static/src/core/l10n/numbers.js index 55e803b4230..c2f024f8ec8 100644 --- a/addons/web/static/src/core/l10n/numbers.js +++ b/addons/web/static/src/core/l10n/numbers.js @@ -4,7 +4,7 @@ import { escapeRegExp, intersperse } from "../utils/strings"; import { localization } from "./localization"; import { _lt } from "./translation"; -class InvalidNumberError extends Error {} +export class InvalidNumberError extends Error {} // ----------------------------------------------------------------------------- // Helpers @@ -136,40 +136,6 @@ export function parseInteger(value) { return parsed; } -/** - * Try to extract a monetary value from a string. The localization is considered in the process. - * The monetary value can have the formats sym$ float, float$ sym or float - * where $  is a non breaking space and sym is a currency symbol. - * If a symbol is found it must correspond to the default currency symbol or to the - * symbol of the currency whose id is passed in options. - * - * @param {string} value - * @param {Object} [options={}] - * @param {number} [options.currencyId] - * @returns {number} float - */ -export function parseMonetary(value, options = {}) { - let values = value.split(" "); - if (values.length === 1) { - return parseFloat(value); - } - let currency; - if (options.currencyId) { - currency = odoo.session_info.currencies[options.currencyId]; - } else { - currency = Object.values(odoo.session_info.currencies)[0]; - } - const symbolIndex = values.findIndex((v) => v === currency.symbol); - if (symbolIndex === -1) { - throw new InvalidNumberError(`"${value}" is not a correct number`); - } - values.splice(symbolIndex, 1); - if (values.length !== 1) { - throw new InvalidNumberError(`"${value}" is not a correct number`); - } - return parseFloat(values[0]); -} - /** * Try to extract a float from a string and unconvert it with a conversion factor of 100. * The localization is considered in the process. diff --git a/addons/web/static/tests/core/l10n/currency_tests.js b/addons/web/static/tests/core/l10n/currency_tests.js index 3d515da6553..fa6c540f55c 100644 --- a/addons/web/static/tests/core/l10n/currency_tests.js +++ b/addons/web/static/tests/core/l10n/currency_tests.js @@ -1,15 +1,18 @@ /** @odoo-module **/ -import { formatCurrency } from "@web/core/l10n/currency"; +import { formatCurrency, parseCurrency } from "@web/core/l10n/currency"; import { localization } from "@web/core/l10n/localization"; import { patch, unpatch } from "@web/core/utils/patch"; import { defaultLocalization } from "../../helpers/mock_services"; +import { patchWithCleanup } from "@web/../tests/helpers/utils"; -QUnit.module("utils", () => { +QUnit.module("utils", (hooks) => { + hooks.beforeEach(() => { + patchWithCleanup(localization, defaultLocalization); + }); QUnit.module("Currency"); QUnit.test("format", async (assert) => { - patch(localization, "locpatch", defaultLocalization); assert.deepEqual(formatCurrency(1234567.654, 1), "$ 1,234,567.65"); assert.deepEqual(formatCurrency(1234567.654, 2), "1,234,567.65 €"); assert.deepEqual( @@ -26,7 +29,46 @@ QUnit.module("utils", () => { "currency digits should take over options digits when both are defined" ); assert.strictEqual(formatCurrency(false, 2), ""); - unpatch(localization, "locpatch"); + }); + + QUnit.test("parseCurrency", function (assert) { + assert.expect(17); + + patchWithCleanup(odoo.session_info, { + currencies: { + 1: { + digits: [69, 2], + position: "after", + symbol: "€", + }, + 3: { + digits: [69, 2], + position: "before", + symbol: "$", + }, + }, + }); + + assert.strictEqual(parseCurrency(""), 0); + assert.strictEqual(parseCurrency("0"), 0); + assert.strictEqual(parseCurrency("100.00 €"), 100); + assert.strictEqual(parseCurrency("-100.00"), -100); + assert.strictEqual(parseCurrency("1,000.00"), 1000); + assert.strictEqual(parseCurrency("1,000,000.00"), 1000000); + assert.strictEqual(parseCurrency("$ 125.00", { currencyId: 3 }), 125); + assert.strictEqual(parseCurrency("1,000.00 €", { currencyId: 1 }), 1000); + + assert.throws(() => parseCurrency(" ", { currencyId: 3 })); + assert.throws(() => parseCurrency("1 ", { currencyId: 3 })); + assert.throws(() => parseCurrency(" 1", { currencyId: 3 })); + + assert.throws(() => parseCurrency("12.00 €")); + assert.throws(() => parseCurrency("$ 12.00", { currencyId: 3 })); + assert.throws(() => parseCurrency("1 $", { currencyId: 1 })); + assert.throws(() => parseCurrency("$ 1")); // "€" is the default currency here + + assert.throws(() => parseCurrency("1$ 1", { currencyId: 1 })); + assert.throws(() => parseCurrency("$ 12.00 34", { currencyId: 3 })); }); // BOI: we do not have a parse method, but here are some tests if we want to add this at some point. diff --git a/addons/web/static/tests/core/l10n/numbers_tests.js b/addons/web/static/tests/core/l10n/numbers_tests.js index 04de9983050..875550a1be2 100644 --- a/addons/web/static/tests/core/l10n/numbers_tests.js +++ b/addons/web/static/tests/core/l10n/numbers_tests.js @@ -7,7 +7,6 @@ import { parseFloat, parseFloatTime, parseInteger, - parseMonetary, parsePercentage, } from "@web/core/l10n/numbers"; import { localization } from "@web/core/l10n/localization"; @@ -129,46 +128,6 @@ QUnit.module("utils", (hooks) => { expectInvalidNumberError(assert, parseInteger, "1.234,567"); }); - QUnit.test("parseMonetary", function (assert) { - assert.expect(17); - - patchWithCleanup(odoo.session_info, { - currencies: { - 1: { - digits: [69, 2], - position: "after", - symbol: "€", - }, - 3: { - digits: [69, 2], - position: "before", - symbol: "$", - }, - }, - }); - - assert.strictEqual(parseMonetary(""), 0); - assert.strictEqual(parseMonetary("0"), 0); - assert.strictEqual(parseMonetary("100.00 €"), 100); - assert.strictEqual(parseMonetary("-100.00"), -100); - assert.strictEqual(parseMonetary("1,000.00"), 1000); - assert.strictEqual(parseMonetary("1,000,000.00"), 1000000); - assert.strictEqual(parseMonetary("$ 125.00", { currencyId: 3 }), 125); - assert.strictEqual(parseMonetary("1,000.00 €", { currencyId: 1 }), 1000); - - expectInvalidNumberError(assert, parseMonetary, " ", { currencyId: 3 }); - expectInvalidNumberError(assert, parseMonetary, "1 ", { currencyId: 3 }); - expectInvalidNumberError(assert, parseMonetary, " 1", { currencyId: 3 }); - - expectInvalidNumberError(assert, parseMonetary, "12.00 €"); - expectInvalidNumberError(assert, parseMonetary, "$ 12.00", { currencyId: 3 }); - expectInvalidNumberError(assert, parseMonetary, "1 $", { currencyId: 1 }); - expectInvalidNumberError(assert, parseMonetary, "$ 1"); // "€" is the default currency here - - expectInvalidNumberError(assert, parseMonetary, "1$ 1", { currencyId: 1 }); - expectInvalidNumberError(assert, parseMonetary, "$ 12.00 34", { currencyId: 3 }); - }); - QUnit.test("parsePercentage", function (assert) { assert.expect(9);