Odoo18-Base/addons/spreadsheet/static/tests/helpers/pivot.js
2025-01-06 10:57:38 +07:00

147 lines
4.7 KiB
JavaScript

import { animationFrame } from "@odoo/hoot-mock";
import { PivotArchParser } from "@web/views/pivot/pivot_arch_parser";
import { OdooPivot } from "@spreadsheet/pivot/odoo_pivot";
import { getBasicPivotArch, getPyEnv } from "@spreadsheet/../tests/helpers/data";
import { createModelWithDataSource } from "@spreadsheet/../tests/helpers/model";
import { waitForDataLoaded } from "@spreadsheet/helpers/model";
import { helpers } from "@odoo/o-spreadsheet";
const { parseDimension, isDateOrDatetimeField } = helpers;
/**
* @typedef {import("@spreadsheet").OdooSpreadsheetModel} OdooSpreadsheetModel
* @typedef {import("@spreadsheet").Zone} Zone
*/
function addEmptyGranularity(dimensions, fields) {
return dimensions.map((dimension) => {
if (dimension.fieldName !== "id" && isDateOrDatetimeField(fields[dimension.fieldName])) {
return {
granularity: "month",
...dimension,
};
}
return dimension;
});
}
/**
* @param {OdooSpreadsheetModel} model
* @param {string} pivotId
* @param {object} params
* @param {string} [params.arch]
* @param {string} [params.resModel]
* @param {object} [params.serverData]
* @param {string} [params.sheetId]
* @param {[number, number]} [params.anchor]
*/
export async function insertPivotInSpreadsheet(model, pivotId, params) {
const archInfo = new PivotArchParser().parse(params.arch || getBasicPivotArch());
const resModel = params.resModel || "partner";
const pyEnv = getPyEnv();
const pivot = {
type: "ODOO",
sortedColumn: null,
domain: [],
context: {},
measures: archInfo.activeMeasures.map((measure) => ({
id: pyEnv[resModel]._fields[measure]?.aggregator
? `${measure}:${pyEnv[resModel]._fields[measure].aggregator}`
: measure,
fieldName: measure,
aggregator: pyEnv[resModel]._fields[measure]?.aggregator,
})),
model: resModel,
columns: addEmptyGranularity(
archInfo.colGroupBys.map(parseDimension),
pyEnv[resModel]._fields
),
rows: addEmptyGranularity(
archInfo.rowGroupBys.map(parseDimension),
pyEnv[resModel]._fields
),
name: "Partner Pivot",
};
model.dispatch("ADD_PIVOT", {
pivotId,
pivot,
});
const ds = model.getters.getPivot(pivotId);
if (!(ds instanceof OdooPivot)) {
throw new Error("The pivot data source is not an OdooPivot");
}
await ds.load();
const { cols, rows, measures, fieldsType } = ds.getTableStructure().export();
const table = {
cols,
rows,
measures,
fieldsType,
};
const [col, row] = params.anchor || [0, 0];
model.dispatch("INSERT_PIVOT", {
pivotId,
sheetId: params.sheetId || model.getters.getActiveSheetId(),
col,
row,
table,
});
await animationFrame();
}
/**
* @param {object} params
* @param {string} [params.arch]
* @param {object} [params.serverData]
* @param {function} [params.mockRPC]
* @returns {Promise<{ model: OdooSpreadsheetModel, env: object, pivotId: string}>}
*/
export async function createSpreadsheetWithPivot(params = {}) {
const model = await createModelWithDataSource({
mockRPC: params.mockRPC,
serverData: params.serverData,
});
const arch = params.arch || getBasicPivotArch();
const pivotId = "PIVOT#1";
await insertPivotInSpreadsheet(model, pivotId, { arch });
const env = model.config.custom.env;
env.model = model;
await waitForDataLoaded(model);
return { model, env, pivotId };
}
/**
* Return the zone that contains all the cells of the given data source
*
* TODO: Un-duplicate this once this or #50623 is merged
*
* @param model
* @param {"pivot" | "list"} dataSourceType
* @param {string} id
* @returns {Zone}
*/
export function getZoneOfInsertedDataSource(model, dataSourceType, id) {
const sheetId = model.getters.getActiveSheetId();
const cells = model.getters.getCells(sheetId);
const positions = Object.keys(cells).map(model.getters.getCellPosition);
let top = 0;
let left = 0;
let bottom = 0;
let right = 0;
for (const position of positions) {
const cellDataSourceId =
dataSourceType === "pivot"
? model.getters.getPivotIdFromPosition({ sheetId, ...position })
: model.getters.getListIdFromPosition({ sheetId, ...position });
if (id !== cellDataSourceId) {
continue;
}
top = Math.min(top, position.row);
left = Math.min(left, position.col);
bottom = Math.max(bottom, position.row);
right = Math.max(right, position.col);
}
return { top, bottom, left, right };
}