From f76205322e2c580cbfabdaf87da9a2328ff93ab6 Mon Sep 17 00:00:00 2001 From: Mathieu Duckerts-Antoine Date: Fri, 1 Jul 2022 10:47:52 +0000 Subject: [PATCH] [FIX] web: graph,pivot: favorite groupbys Problem: Have a pivot view in some state. Toggle a favorite with a context in which a key "pivot_row_groupby" is defined. The pivot view should be grouped (on rows) by that pivot_row_groupby but it is not always the case. The basic problem is that the key "pivot_row_groupby" is never considered after the first load (see method load in pivot_model.js). Solution: We make the search model used by the pivot view send as groupby for the favorite its pivot_row_groupby instead of its groupBy (which can be different). We do something similar for the graph view that presents a similar problem. closes odoo/odoo#95688 Opw: 2837428 X-original-commit: ea9f66f99caaa6136912c467e5b80fe605586845 Signed-off-by: Mathieu Duckerts-Antoine Signed-off-by: Aaron Bohy (aab) --- .../src/views/graph/graph_search_model.js | 21 +++ .../web/static/src/views/graph/graph_view.js | 2 + .../src/views/pivot/pivot_search_model.js | 25 +++ .../web/static/src/views/pivot/pivot_view.js | 2 + .../static/tests/views/graph_view_tests.js | 39 +++++ .../static/tests/views/pivot_view_tests.js | 160 ++++++++++++++++++ 6 files changed, 249 insertions(+) create mode 100644 addons/web/static/src/views/graph/graph_search_model.js create mode 100644 addons/web/static/src/views/pivot/pivot_search_model.js diff --git a/addons/web/static/src/views/graph/graph_search_model.js b/addons/web/static/src/views/graph/graph_search_model.js new file mode 100644 index 00000000000..ab76cf1831c --- /dev/null +++ b/addons/web/static/src/views/graph/graph_search_model.js @@ -0,0 +1,21 @@ +/** @odoo-module **/ + +import { SearchModel } from "@web/search/search_model"; + +export class GraphSearchModel extends SearchModel { + _getIrFilterDescription() { + this.preparingIrFilterDescription = true; + const result = super._getIrFilterDescription(...arguments); + this.preparingIrFilterDescription = false; + return result; + } + + _getSearchItemGroupBys(activeItem) { + const { searchItemId } = activeItem; + const { context, type } = this.searchItems[searchItemId]; + if (!this.preparingIrFilterDescription && type === "favorite" && context.graph_groupbys) { + return context.graph_groupbys; + } + return super._getSearchItemGroupBys(...arguments); + } +} diff --git a/addons/web/static/src/views/graph/graph_view.js b/addons/web/static/src/views/graph/graph_view.js index 088ae71a40f..9d93e085ab8 100644 --- a/addons/web/static/src/views/graph/graph_view.js +++ b/addons/web/static/src/views/graph/graph_view.js @@ -6,6 +6,7 @@ import { GraphArchParser } from "./graph_arch_parser"; import { GraphModel } from "./graph_model"; import { GraphController } from "./graph_controller"; import { GraphRenderer } from "./graph_renderer"; +import { GraphSearchModel } from "./graph_search_model"; const viewRegistry = registry.category("views"); @@ -18,6 +19,7 @@ export const graphView = { Renderer: GraphRenderer, Model: GraphModel, ArchParser: GraphArchParser, + SearchModel: GraphSearchModel, searchMenuTypes: ["filter", "groupBy", "comparison", "favorite"], buttonTemplate: "web.GraphView.Buttons", diff --git a/addons/web/static/src/views/pivot/pivot_search_model.js b/addons/web/static/src/views/pivot/pivot_search_model.js new file mode 100644 index 00000000000..ffe46a6bb6b --- /dev/null +++ b/addons/web/static/src/views/pivot/pivot_search_model.js @@ -0,0 +1,25 @@ +/** @odoo-module **/ + +import { SearchModel } from "@web/search/search_model"; + +export class PivotSearchModel extends SearchModel { + _getIrFilterDescription() { + this.preparingIrFilterDescription = true; + const result = super._getIrFilterDescription(...arguments); + this.preparingIrFilterDescription = false; + return result; + } + + _getSearchItemGroupBys(activeItem) { + const { searchItemId } = activeItem; + const { context, type } = this.searchItems[searchItemId]; + if ( + !this.preparingIrFilterDescription && + type === "favorite" && + context.pivot_row_groupby + ) { + return context.pivot_row_groupby; + } + return super._getSearchItemGroupBys(...arguments); + } +} diff --git a/addons/web/static/src/views/pivot/pivot_view.js b/addons/web/static/src/views/pivot/pivot_view.js index d8ea9e95521..0bf46ca0a18 100644 --- a/addons/web/static/src/views/pivot/pivot_view.js +++ b/addons/web/static/src/views/pivot/pivot_view.js @@ -6,6 +6,7 @@ import { PivotArchParser } from "@web/views/pivot/pivot_arch_parser"; import { PivotController } from "./pivot_controller"; import { PivotModel } from "@web/views/pivot/pivot_model"; import { PivotRenderer } from "@web/views/pivot/pivot_renderer"; +import { PivotSearchModel } from "./pivot_search_model"; const viewRegistry = registry.category("views"); @@ -18,6 +19,7 @@ export const pivotView = { Renderer: PivotRenderer, Model: PivotModel, ArchParser: PivotArchParser, + SearchModel: PivotSearchModel, searchMenuTypes: ["filter", "groupBy", "comparison", "favorite"], buttonTemplate: "web.PivotView.Buttons", diff --git a/addons/web/static/tests/views/graph_view_tests.js b/addons/web/static/tests/views/graph_view_tests.js index a472dd8cf64..0ea43c26c76 100644 --- a/addons/web/static/tests/views/graph_view_tests.js +++ b/addons/web/static/tests/views/graph_view_tests.js @@ -3676,4 +3676,43 @@ QUnit.module("Views", (hooks) => { }); checkLabels(assert, graph, ["January 2016", "March 2016", "May 2016", "April 2016"]); }); + + QUnit.test("graph_groupbys should be also used after first load", async function (assert) { + const graph = await makeView({ + serverData, + type: "graph", + resModel: "foo", + groupBy: ["date:quarter"], + arch: ``, + irFilters: [ + { + user_id: [2, "Mitchell Admin"], + name: "Favorite", + id: 1, + context: `{ + "group_by": [], + "graph_measure": "revenue", + "graph_mode": "bar", + "graph_groupbys": ["color_id"], + }`, + sort: "[]", + domain: "", + is_default: false, + model_id: "foo", + action_id: false, + }, + ], + }); + + checkModeIs(assert, graph, "bar"); + checkLabels(assert, graph, ["Q1 2016", "Q2 2016", "Undefined"]); + checkLegend(assert, graph, "Count"); + + await toggleFavoriteMenu(target); + await toggleMenuItem(target, "Favorite"); + + checkModeIs(assert, graph, "bar"); + checkLabels(assert, graph, ["Undefined", "red"]); + checkLegend(assert, graph, "Revenue"); + }); }); diff --git a/addons/web/static/tests/views/pivot_view_tests.js b/addons/web/static/tests/views/pivot_view_tests.js index 870ec97919b..e2dea0351e7 100644 --- a/addons/web/static/tests/views/pivot_view_tests.js +++ b/addons/web/static/tests/views/pivot_view_tests.js @@ -5383,4 +5383,164 @@ QUnit.module("Views", (hooks) => { assert.strictEqual(getCurrentValues(target), values.join()); } ); + + QUnit.test("pivot_row_groupby should be also used after first load", async function (assert) { + const ids = [1, 2]; + const expectedContexts = [ + { + group_by: ["bar"], + pivot_column_groupby: [], + pivot_measures: ["__count"], + pivot_row_groupby: ["product_id"], + }, + { + group_by: ["bar", "customer"], + pivot_column_groupby: [], + pivot_measures: ["__count"], + pivot_row_groupby: ["customer"], + }, + ]; + + await makeView({ + type: "pivot", + resModel: "partner", + serverData, + arch: ``, + searchViewArch: ` + + + + + `, + groupBy: ["bar"], + mockRPC(route, args) { + if (args.method === "create_or_replace") { + assert.deepEqual(args.args[0].context, expectedContexts.shift()); + return ids.shift(); + } + }, + }); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "No", "Yes"], + "The row headers should be as expected" + ); + + await click(target.querySelector("tbody th")); // click on row header "Total" + await click(target.querySelector("tbody th")); // click on row header "Total" + await click(target.querySelector("tbody .o_group_by_menu .o_menu_item")); // select "Product" + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "xphone", "xpad"], + "The row headers should be as expected" + ); + + await toggleFavoriteMenu(target); + await toggleSaveFavorite(target); + await editFavoriteName(target, "Favorite"); + await saveFavorite(target); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "xphone", "xpad"], + "The row headers should be as expected" + ); + + await removeFacet(target); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "No", "Yes"], + "The row headers should be as expected" + ); + + await toggleFavoriteMenu(target); + await toggleMenuItem(target, "Favorite"); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "xphone", "xpad"], + "The row headers should be as expected" + ); + + await toggleGroupByMenu(target); + await toggleMenuItem(target, "Customer"); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "xphone", "First", "xpad", "First", "Second"], + "The row headers should be as expected" + ); + + await click(target.querySelector("tbody th")); // click on row header "Total" + await click(target.querySelector("tbody th")); // click on row header "Total" + await click(target.querySelectorAll("tbody .o_group_by_menu .o_menu_item")[1]); // select "Customer" + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "First", "Second"], + "The row headers should be as expected" + ); + + await toggleFavoriteMenu(target); + await toggleSaveFavorite(target); + await editFavoriteName(target, "Favorite 2"); + await saveFavorite(target); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "First", "Second"], + "The row headers should be as expected" + ); + }); + + QUnit.test( + "pivot_row_groupby should be also used after first load (2)", + async function (assert) { + await makeView({ + serverData, + type: "pivot", + resModel: "partner", + groupBy: ["product_id"], + arch: ``, + irFilters: [ + { + user_id: [2, "Mitchell Admin"], + name: "Favorite", + id: 1, + context: ` + { + "group_by": [], + "pivot_row_groupby": ["customer"], + "pivot_col_groupby": [], + "pivot_measures": ["foo"], + } + `, + sort: "[]", + domain: "", + is_default: false, + model_id: "foo", + action_id: false, + }, + ], + }); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "xphone", "xpad"], + "The row headers should be as expected" + ); + + await toggleFavoriteMenu(target); + await toggleMenuItem(target, "Favorite"); + + assert.deepEqual( + [...target.querySelectorAll("th")].slice(3).map((el) => el.innerText), + ["Total", "First", "Second"], + "The row headers should be as expected" + ); + } + ); });