Files
odoo_source/addons/spreadsheet/static/tests/utils/getters.js
T
Adrien MinneandLucas Lefèvre 442e8a23ae [IMP] spreadsheet: add ODOO.PIVOT.TABLE function
This commit introduces a new pivot function:

ODOO.PIVOT.TABLE(<pivot_id>, [row_count], [include_total], [include_column_headers])

Purpose
-------
It answers several current limitations:
- The pivot in spreadsheet not being "dynamic" (growing as new groups/records
  are created) is a *very* frequent feedback

- sorted pivots are very cumbersome (# syntax) and takes a lot of cells

- cannot easily compute arbitrary aggregates (max, avg). You only get the
  total. ... as soon as new groups appears that are not reflected in the
  spreadsheet, you can't guess data is missing and that it's not taken into
  account.

Specification
-------------
Add a single and simple function =ODOO.PIVOT.TABLE(<pivot_id>) that would
display the entire table (dynamic, as more groups and records are added).

We can achieve almost everything we want:
- by combining with other functions (INDEX, CHOOSECOLS, CHOOSEROWS, XLOOKUP,
  ...) if we want to target a specific row or column.

- by using infinite ranges (e.g. =MAX(B2:B)) to account for a growing table

- we could remove all the positional PIVOT version of the function
  (=ODOO.PIVOT.HEADER(7,"#country_id",1)). The implementation is a mess
  (lots of ifs everywhere to account for the #). Just replace it by a single
  function SORT(ODOO.PIVOT.TABLE(1), 1) (or with NSORT, or sorted from the
  pivot view directly)

For some situations though, there would be the "Totals" in the way:
if you want =MAX(ODOO.PIVOT.TABLE(1)), you don't want to have totals in the
way (with infinite ranges). We add an optional parameter 'include_total'
(default to true)

For dashboards, we want to have custom header names, we don't want to use
the headers from the pivot. To only have data and not the headers:
new parameter 'include_column_headers' (default to true)

All in all: here is what it looks like:

ODOO.PIVOT.TABLE(<pivot_id>, [row_count], [include_total], [include_column_headers])

Task: 3318865
Part-of: odoo/odoo#138594
Co-authored-by: Lucas Lefèvre <lul@odoo.com>
2023-10-20 14:59:19 +00:00

98 lines
3.1 KiB
JavaScript

/** @odoo-module */
import * as spreadsheet from "@odoo/o-spreadsheet";
import { range } from "@web/core/utils/numbers";
const { toCartesian, toZone } = spreadsheet.helpers;
/**
* Get the value of the given cell
*/
export function getCellValue(model, xc, sheetId = model.getters.getActiveSheetId()) {
const { col, row } = toCartesian(xc);
const cell = model.getters.getEvaluatedCell({ sheetId, col, row });
return cell.value;
}
/**
* Get the cell of the given xc
*/
export function getCell(model, xc, sheetId = model.getters.getActiveSheetId()) {
const { col, row } = toCartesian(xc);
return model.getters.getCell({ sheetId, col, row });
}
export function getEvaluatedCell(model, xc, sheetId = model.getters.getActiveSheetId()) {
const { col, row } = toCartesian(xc);
return model.getters.getEvaluatedCell({ sheetId, col, row });
}
export function getEvaluatedGrid(model, zoneXc, sheetId = model.getters.getActiveSheetId()) {
const { top, bottom, left, right } = toZone(zoneXc);
const grid = [];
for (const row of range(top, bottom + 1)) {
grid.push([]);
for (const col of range(left, right + 1)) {
const cell = model.getters.getEvaluatedCell({ sheetId, col, row });
grid[row][col] = cell.value;
}
}
return grid;
}
export function getEvaluatedFormatGrid(model, zoneXc, sheetId = model.getters.getActiveSheetId()) {
const { top, bottom, left, right } = toZone(zoneXc);
const grid = [];
for (const row of range(top, bottom + 1)) {
grid.push([]);
for (const col of range(left, right + 1)) {
const cell = model.getters.getEvaluatedCell({ sheetId, col, row });
grid[row][col] = cell.format;
}
}
return grid;
}
/**
* Get the cells of the given sheet (or active sheet if not provided)
*/
export function getCells(model, sheetId = model.getters.getActiveSheetId()) {
return model.getters.getCells(sheetId);
}
/**
* Get the formula of the given xc
*/
export function getCellFormula(model, xc, sheetId = model.getters.getActiveSheetId()) {
const cell = getCell(model, xc, sheetId);
return cell && cell.isFormula ? model.getters.getFormulaCellContent(sheetId, cell) : "";
}
/**
* Get the content of the given xc
*/
export function getCellContent(model, xc, sheetId = model.getters.getActiveSheetId()) {
const { col, row } = toCartesian(xc);
return model.getters.getCellText({ sheetId, col, row }, true);
}
/**
* Get the list of the merges (["A1:A2"]) of the sheet
*/
export function getMerges(model, sheetId = model.getters.getActiveSheetId()) {
return model.exportData().sheets.find((sheet) => sheet.id === sheetId).merges;
}
/**
* Get the borders at the given XC
*/
export function getBorders(model, xc, sheetId = model.getters.getActiveSheetId()) {
const { col, row } = toCartesian(xc);
const borders = model.getters.getCellBorder({ sheetId, col, row });
if (!borders) {
return null;
}
Object.keys(borders).forEach((key) => borders[key] === undefined && delete borders[key]);
return borders;
}