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;