From 0111317b758b87bbe9ef551cdc055b1deec32091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Lef=C3=A8vre=20=28lul=29?= Date: Thu, 11 Jan 2024 16:52:02 +0100 Subject: [PATCH] [FIX] spreadsheet: accumulate starting with past data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Inserting a cumulated graph view inside spreadsheet (e.g. cumulated subscription MRR breakdown), - apply a global filter to filter, let's say on the current month => the first data point does not include data from before the current month (the accumulation starts at 0, even though there is data before) You can also check the MRR evolution subscription dashboard, "MRR over time" chart. Note: with this fix, we assume all "cumulated" charts are also "cumulated_start". Which is true in practice (only one cumulated graph view in the entire codebase) closes odoo/odoo#149084 Task: 3680601 Related: odoo/enterprise#54146 Signed-off-by: Lucas Lefèvre (lul) --- .../static/src/chart/odoo_chart/odoo_chart.js | 15 ++++-- .../src/chart/odoo_chart/odoo_line_chart.js | 4 +- .../charts/model/odoo_chart_plugin_test.js | 47 +++++++++++++++++++ .../spreadsheet/static/tests/utils/chart.js | 17 ++++--- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/addons/spreadsheet/static/src/chart/odoo_chart/odoo_chart.js b/addons/spreadsheet/static/src/chart/odoo_chart/odoo_chart.js index 9d3db888357..01b001b7f6a 100644 --- a/addons/spreadsheet/static/src/chart/odoo_chart/odoo_chart.js +++ b/addons/spreadsheet/static/src/chart/odoo_chart/odoo_chart.js @@ -22,6 +22,7 @@ import { ChartDataSource } from "../data_source/chart_data_source"; * @property {string} title * @property {string} background * @property {string} legendPosition + * @property {boolean} cumulative * * @typedef OdooChartDefinitionDataSource * @property {MetaData} metaData @@ -38,7 +39,14 @@ export class OdooChart extends AbstractChart { constructor(definition, sheetId, getters) { super(definition, sheetId, getters); this.type = definition.type; - this.metaData = definition.metaData; + this.metaData = { + ...definition.metaData, + mode: this.type.replace("odoo_", ""), + cumulated: definition.cumulative, + // if a chart is cumulated, the first data point should take into + // account past data, even if a domain on a specific period is applied + cumulatedStart: definition.cumulative, + }; this.searchParams = definition.searchParams; this.legendPosition = definition.legendPosition; this.background = definition.background; @@ -62,10 +70,7 @@ export class OdooChart extends AbstractChart { */ getDefinitionForDataSource() { return { - metaData: { - ...this.metaData, - mode: this.type.replace("odoo_", ""), - }, + metaData: this.metaData, searchParams: this.searchParams, }; } diff --git a/addons/spreadsheet/static/src/chart/odoo_chart/odoo_line_chart.js b/addons/spreadsheet/static/src/chart/odoo_chart/odoo_line_chart.js index 48c7740547e..96114b2f2b3 100644 --- a/addons/spreadsheet/static/src/chart/odoo_chart/odoo_line_chart.js +++ b/addons/spreadsheet/static/src/chart/odoo_chart/odoo_line_chart.js @@ -51,7 +51,7 @@ function createOdooChartRuntime(chart, getters) { const locale = getters.getLocale(); const chartJsConfig = getLineConfiguration(chart, labels, locale); const colors = new ChartColors(); - for (let [index, { label, data }] of datasets.entries()) { + for (let [index, { label, data, cumulatedStart }] of datasets.entries()) { const color = colors.next(); const backgroundRGBA = colorToRGBA(color); if (chart.stacked) { @@ -59,7 +59,7 @@ function createOdooChartRuntime(chart, getters) { backgroundRGBA.a = LINE_FILL_TRANSPARENCY; } if (chart.cumulative) { - let accumulator = 0; + let accumulator = cumulatedStart; data = data.map((value) => { accumulator += value; return accumulator; diff --git a/addons/spreadsheet/static/tests/charts/model/odoo_chart_plugin_test.js b/addons/spreadsheet/static/tests/charts/model/odoo_chart_plugin_test.js index 0899a8eafa3..a6c4f38629b 100644 --- a/addons/spreadsheet/static/tests/charts/model/odoo_chart_plugin_test.js +++ b/addons/spreadsheet/static/tests/charts/model/odoo_chart_plugin_test.js @@ -12,6 +12,7 @@ import { THIS_YEAR_GLOBAL_FILTER } from "../../utils/global_filter"; import * as spreadsheet from "@odoo/o-spreadsheet"; import { makeServerError } from "@web/../tests/helpers/mock_server"; import { session } from "@web/session"; +import { getBasicServerData } from "../../utils/data"; const { toZone } = spreadsheet.helpers; @@ -523,6 +524,52 @@ QUnit.module("spreadsheet > odoo chart plugin", {}, () => { ); }); + QUnit.test("cumulative line chart with past data before domain period", async (assert) => { + const serverData = getBasicServerData(); + serverData.models.partner.records = [ + { date: "2020-01-01", probability: 10 }, + { date: "2021-01-01", probability: 2 }, + { date: "2022-01-01", probability: 3 }, + { date: "2022-03-01", probability: 4 }, + { date: "2022-06-01", probability: 5 }, + ]; + const { model } = await createSpreadsheetWithChart({ + type: "odoo_line", + serverData, + definition: { + type: "odoo_line", + metaData: { + groupBy: ["date"], + measure: "probability", + order: null, + resModel: "partner", + }, + searchParams: { + comparison: null, + context: {}, + domain: [ + ["date", ">=", "2022-01-01"], + ["date", "<=", "2022-12-31"], + ], + groupBy: [], + orderBy: [], + }, + cumulative: true, + title: "Partners", + dataSourceId: "42", + id: "42", + }, + }); + const sheetId = model.getters.getActiveSheetId(); + const chartId = model.getters.getChartIds(sheetId)[0]; + await waitForDataSourcesLoaded(model); + + assert.deepEqual( + model.getters.getChartRuntime(chartId).chartJsConfig.data.datasets[0].data, + [15, 19, 24] + ); + }); + QUnit.test("Can insert odoo chart from a different model", async (assert) => { const model = await createModelWithDataSource(); insertListInSpreadsheet(model, { model: "product", columns: ["name"] }); diff --git a/addons/spreadsheet/static/tests/utils/chart.js b/addons/spreadsheet/static/tests/utils/chart.js index d1862e9ab9f..018b36b339a 100644 --- a/addons/spreadsheet/static/tests/utils/chart.js +++ b/addons/spreadsheet/static/tests/utils/chart.js @@ -10,9 +10,14 @@ const uuidGenerator = new spreadsheet.helpers.UuidGenerator(); /** * * @param {Model} model + * @param {string} type + * @param {import("@spreadsheet/chart/odoo_chart/odoo_chart").OdooChartDefinition} definition */ -export function insertChartInSpreadsheet(model, type = "odoo_bar") { - const definition = getChartDefinition(type); +export function insertChartInSpreadsheet( + model, + type = "odoo_bar", + definition = getChartDefinition(type) +) { model.dispatch("CREATE_CHART", { sheetId: model.getters.getActiveSheetId(), id: definition.id, @@ -26,17 +31,17 @@ export function insertChartInSpreadsheet(model, type = "odoo_bar") { /** * * @param {Object} params + * @param {function} [params.definition] * @param {function} [params.mockRPC] * @param {string} [params.type] + * @param {import("./data").ServerData} [params.serverData] * * @returns { Promise<{ model: Model, env: Object }>} */ export async function createSpreadsheetWithChart(params = {}) { - const model = await createModelWithDataSource({ - mockRPC: params.mockRPC, - }); + const model = await createModelWithDataSource(params); - insertChartInSpreadsheet(model, params.type); + insertChartInSpreadsheet(model, params.type, params.definition); const env = model.config.custom.env; env.model = model;