diff --git a/addons/web/static/src/views/graph/graph_model.js b/addons/web/static/src/views/graph/graph_model.js index 9f9f7744667..a5103051f1e 100644 --- a/addons/web/static/src/views/graph/graph_model.js +++ b/addons/web/static/src/views/graph/graph_model.js @@ -431,7 +431,7 @@ export class GraphModel extends Model { label = `${val}`; // toUpperCase? } else if (val === false) { label = this.env._t("Undefined"); - } else if (type === "many2one") { + } else if (["many2many", "many2one"].includes(type)) { const [id, name] = val; const key = JSON.stringify([fieldName, name]); if (!numbering[key]) { @@ -501,9 +501,10 @@ export class GraphModel extends Model { const processedGroupBy = []; for (const gb of groupBy) { const { fieldName, interval } = gb; - const { sortable, type } = fields[fieldName]; + const { sortable, type, store } = fields[fieldName]; if ( - !sortable || + // many2many is groupable precisely when it is stored (cf. groupable in odoo/fields.py) + (type === "many2many" ? !store : !sortable) || ["id", "__count"].includes(fieldName) || !GROUPABLE_TYPES.includes(type) ) { diff --git a/addons/web/static/tests/views/graph_view_tests.js b/addons/web/static/tests/views/graph_view_tests.js index 74862fc4df2..400540d08c2 100644 --- a/addons/web/static/tests/views/graph_view_tests.js +++ b/addons/web/static/tests/views/graph_view_tests.js @@ -193,6 +193,12 @@ QUnit.module("Views", (hooks) => { group_operator: "sum", sortable: true, }, + color_ids: { + string: "Colors", + type: "many2many", + relation: "color", + store: true, + }, }, records: [ { @@ -202,6 +208,7 @@ QUnit.module("Views", (hooks) => { product_id: 37, date: "2016-01-01", revenue: 1, + color_ids: [7], }, { id: 2, @@ -211,6 +218,7 @@ QUnit.module("Views", (hooks) => { color_id: 7, date: "2016-01-03", revenue: 2, + color_ids: [14], }, { id: 3, @@ -219,6 +227,7 @@ QUnit.module("Views", (hooks) => { product_id: 37, date: "2016-03-04", revenue: 3, + color_ids: [7, 14], }, { id: 4, @@ -227,6 +236,7 @@ QUnit.module("Views", (hooks) => { product_id: 37, date: "2016-03-07", revenue: 4, + color_ids: [7], }, { id: 5, @@ -235,6 +245,7 @@ QUnit.module("Views", (hooks) => { product_id: 41, date: "2016-05-01", revenue: 5, + color_ids: [7, 14], }, { id: 6, foo: 63, bar: false, product_id: 41 }, { id: 7, foo: 42, bar: false, product_id: 41 }, @@ -550,6 +561,96 @@ QUnit.module("Views", (hooks) => { ); }); + QUnit.test("bar chart many2many groupBy", async function (assert) { + assert.expect(16); + const graph = await makeView({ + serverData, + type: "graph", + resModel: "foo", + arch: ` + + + + `, + }); + assert.containsOnce(target, "div.o_graph_canvas_container canvas"); + checkLabels(assert, graph, ["Undefined", "black", "red"]); + checkDatasets(assert, graph, ["backgroundColor", "borderColor", "data", "label"], { + backgroundColor: "#1f77b4", + borderColor: undefined, + data: [8, 10, 13], + label: "Revenue", + }); + checkLegend(assert, graph, "Revenue"); + checkTooltip( + assert, + graph, + { lines: [{ label: "Undefined", value: "8" }], title: "Revenue" }, + 0 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "black", value: "10" }], title: "Revenue" }, + 1 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "red", value: "13" }], title: "Revenue" }, + 2 + ); + }); + + QUnit.test("differentiate many2many values with same label", async function (assert) { + assert.expect(19); + serverData.models.color.records.push({ id: 21, display_name: "red" }); + serverData.models.foo.records.push({ id: 30, color_ids: [21], revenue: 14 }); + const graph = await makeView({ + serverData, + type: "graph", + resModel: "foo", + arch: ` + + + + `, + }); + assert.containsOnce(target, "div.o_graph_canvas_container canvas"); + checkLabels(assert, graph, ["Undefined", "black", "red", "red (2)"]); + checkDatasets(assert, graph, ["backgroundColor", "borderColor", "data", "label"], { + backgroundColor: "#1f77b4", + borderColor: undefined, + data: [8, 10, 14, 13], + label: "Revenue", + }); + + checkTooltip( + assert, + graph, + { lines: [{ label: "Undefined", value: "8" }], title: "Revenue" }, + 0 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "black", value: "10" }], title: "Revenue" }, + 1 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "red", value: "14" }], title: "Revenue" }, + 2 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "red (2)", value: "13" }], title: "Revenue" }, + 3 + ); + }); + QUnit.test( "bar chart rendering (one groupBy, several domains with date identification)", async function (assert) { @@ -887,6 +988,42 @@ QUnit.module("Views", (hooks) => { ); }); + QUnit.test("line chart many2many groupBy", async function (assert) { + assert.expect(12); + const graph = await makeView({ + serverData, + type: "graph", + resModel: "foo", + arch: ` + + + + + `, + }); + assert.containsOnce(target, "div.o_graph_canvas_container canvas"); + checkLabels(assert, graph, ["black", "red"]); + checkDatasets(assert, graph, ["backgroundColor", "borderColor", "data", "label"], { + backgroundColor: "rgba(31,119,180,0.4)", + borderColor: "#1f77b4", + data: [10, 13], + label: "Revenue", + }); + checkLegend(assert, graph, "Revenue"); + checkTooltip( + assert, + graph, + { lines: [{ label: "black", value: "10" }], title: "Revenue" }, + 0 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "red", value: "13" }], title: "Revenue" }, + 1 + ); + }); + QUnit.test("Stacked button visible in the line chart", async function (assert) { const graph = await makeView({ serverData, @@ -1506,6 +1643,47 @@ QUnit.module("Views", (hooks) => { checkTooltip(assert, graph, { lines: [{ label: "true", value: "3 (37.50%)" }] }, 1); }); + QUnit.test("pie chart many2many groupby", async function (assert) { + assert.expect(16); + const graph = await makeView({ + serverData, + type: "graph", + resModel: "foo", + arch: ` + + + + + `, + }); + assert.containsOnce(target, "div.o_graph_canvas_container canvas"); + checkLabels(assert, graph, ["Undefined", "black", "red"]); + checkDatasets(assert, graph, ["backgroundColor", "borderColor", "data"], { + backgroundColor: ["#1f77b4", "#ff7f0e", "#aec7e8"], + borderColor: BORDER_WHITE, + data: [8, 10, 13], + }); + checkLegend(assert, graph, ["Undefined", "black", "red"]); + checkTooltip( + assert, + graph, + { lines: [{ label: "Undefined", value: "8 (25.81%)" }], title: "Revenue" }, + 0 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "black", value: "10 (32.26%)" }], title: "Revenue" }, + 1 + ); + checkTooltip( + assert, + graph, + { lines: [{ label: "red", value: "13 (41.94%)" }], title: "Revenue" }, + 2 + ); + }); + QUnit.test("pie chart rendering (two groupBy)", async function (assert) { assert.expect(16); const graph = await makeView({