[FIX] web: Fix computation of aggregates in list_renderer

This commit fixes how monetary fields are handled when doing aggregates in list view:
aggregates should not be computed when all values are not in the same currency and
the currency should be displayed with the aggregate when this is not the case.

closes odoo/odoo#116556

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
Julien Carion (juca)
2023-04-19 12:13:22 +02:00
parent f5ff0b1b30
commit e96566e11d
2 changed files with 134 additions and 2 deletions
@@ -30,6 +30,7 @@ import {
useRef,
useState,
} from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
const formatters = registry.category("formatters");
@@ -604,6 +605,33 @@ export class ListRenderer extends Component {
if (type !== "integer" && type !== "float" && type !== "monetary") {
continue;
}
let currencyId;
if (type === "monetary") {
const currencyField =
this.props.list.activeFields[column.name].options.currency_field ||
this.fields[column.name].currency_field ||
"currency_id";
if (!(currencyField in this.props.list.activeFields)) {
aggregates[fieldName] = {
help: _t("No currency provided"),
value: "—",
};
continue;
}
currencyId = values[0][currencyField]?.[0];
if (currencyId) {
const sameCurrency = values.every(
(value) => currencyId === value[currencyField][0]
);
if (!sameCurrency) {
aggregates[fieldName] = {
help: _t("Different currencies cannot be aggregated"),
value: "—",
};
continue;
}
}
}
const { attrs, widget } = column;
const func =
(attrs.sum && "sum") ||
@@ -628,6 +656,9 @@ export class ListRenderer extends Component {
digits: attrs.digits ? JSON.parse(attrs.digits) : undefined,
escape: true,
};
if (currencyId) {
formatOptions.currencyId = currencyId;
}
aggregates[fieldName] = {
help: attrs[func],
value: formatter ? formatter(aggregateValue, formatOptions) : aggregateValue,
@@ -124,6 +124,12 @@ QUnit.module("Views", (hooks) => {
relation: "res_currency",
default: 1,
},
currency_test: {
string: "Currency",
type: "many2one",
relation: "res_currency",
default: 1,
},
company_currency_id: {
string: "Company Currency",
type: "many2one",
@@ -3592,11 +3598,101 @@ QUnit.module("Views", (hooks) => {
);
assert.strictEqual(
target.querySelectorAll("tfoot td")[1].textContent,
"2000.000",
"aggregates monetary use digits attribute if available"
"—",
"aggregates monetary should never work if no currency field is present"
);
});
QUnit.test("aggregates monetary (same currency)", async function (assert) {
serverData.models.foo.records[0].currency_id = 1;
await makeView({
type: "list",
resModel: "foo",
serverData,
arch: `
<tree>
<field name="amount" widget="monetary" sum="Sum"/>
<field name="currency_id"/>
</tree>`,
});
assert.deepEqual(getNodesTextContent(target.querySelectorAll("tbody .o_monetary_cell")), [
"$\u00a01200.00",
"$\u00a0500.00",
"$\u00a0300.00",
"$\u00a00.00",
]);
assert.strictEqual(target.querySelectorAll("tfoot td")[1].textContent, "$\u00a02000.00");
});
QUnit.test("aggregates monetary (different currencies)", async function (assert) {
await makeView({
type: "list",
resModel: "foo",
serverData,
arch: `
<tree>
<field name="amount" widget="monetary" sum="Sum"/>
<field name="currency_id"/>
</tree>`,
});
assert.deepEqual(getNodesTextContent(target.querySelectorAll("tbody .o_monetary_cell")), [
"1200.00\u00a0€",
"$\u00a0500.00",
"$\u00a0300.00",
"$\u00a00.00",
]);
assert.strictEqual(target.querySelectorAll("tfoot td")[1].textContent, "—");
});
QUnit.test("aggregates monetary (currency field not in view)", async function (assert) {
await makeView({
type: "list",
resModel: "foo",
serverData,
arch: `
<tree>
<field name="amount" widget="monetary" sum="Sum" options="{'currency_field': 'currency_test'}"/>
<field name="currency_id"/>
</tree>`,
});
assert.deepEqual(getNodesTextContent(target.querySelectorAll("tbody .o_monetary_cell")), [
"1200.00",
"500.00",
"300.00",
"0.00",
]);
assert.strictEqual(target.querySelectorAll("tfoot td")[1].textContent, "—");
});
QUnit.test("aggregates monetary (currency field in view)", async function (assert) {
serverData.models.foo.fields.amount.currency_field = "currency_test";
await makeView({
type: "list",
resModel: "foo",
serverData,
arch: `
<tree>
<field name="amount" widget="monetary" sum="Sum"/>
<field name="currency_test"/>
</tree>`,
});
assert.deepEqual(getNodesTextContent(target.querySelectorAll("tbody .o_monetary_cell")), [
"$\u00a01200.00",
"$\u00a0500.00",
"$\u00a0300.00",
"$\u00a00.00",
]);
assert.strictEqual(target.querySelectorAll("tfoot td")[1].textContent, "$\u00a02000.00");
});
QUnit.test(
"currency_field is taken into account when formatting monetary values",
async (assert) => {
@@ -3623,6 +3719,11 @@ QUnit.module("Views", (hooks) => {
"$\u00a01100.00",
"field should be formatted based on company_currency_id"
);
assert.strictEqual(
target.querySelectorAll("tfoot td")[1].textContent,
"—",
"aggregates monetary should never work if different currencies are used"
);
}
);