Skip to content

[IMP] formulas: add the SUBTOTAL function #6774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

laa-odoo
Copy link
Collaborator

@laa-odoo laa-odoo commented Jul 8, 2025

Task: 4873384

@robodoo
Copy link
Collaborator

robodoo commented Jul 8, 2025

Pull request status dashboard

@laa-odoo laa-odoo force-pushed the master-add-subtotal-formula-laa branch 6 times, most recently from 29f0eec to 43c8aed Compare July 25, 2025 14:38
@rrahir
Copy link
Collaborator

rrahir commented Jul 26, 2025

Yeah!🎉

@laa-odoo laa-odoo force-pushed the master-add-subtotal-formula-laa branch from 43c8aed to e42c127 Compare July 28, 2025 12:28
@@ -35962,6 +36293,11 @@ exports[`Test XLSX export formulas Multi-Sheets exportable functions 1`] = `
>25
</t>
</si>
<si>
<t>
=ROW(A234)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you know where this comes from ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using ROW and COLUMN for references that do not exist on the sheet no longer works.
The test has been changed so that it continues to work on an existing reference.

"Returns a subtotal for a vertical range of cells using a specified aggregation function."
),
args: [
arg("function_code (number)", _t("The function to use in subtotal aggregation.")),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add what are the possible codes ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to do in another commit for all formulas that accept static parameters

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in a TOFIXUP commit

const bottom = top + ref[0].length - 1;

for (let row = top; row <= bottom; row++) {
if (this.getters.isRowFiltered(sheetId, row)) continue;
Copy link
Collaborator

@LucasLefevre LucasLefevre Jul 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, all commands related to filters and hidden headers need to invalidate the evaluation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in the commit "TOFIXUP"

@laa-odoo laa-odoo force-pushed the master-add-subtotal-formula-laa branch 2 times, most recently from 01b8dde to 5d69db4 Compare August 4, 2025 07:56
Why this commit ?

We would like to introduce the SUBTOTAL formula:
This formula has the particularity of taking meta arguments as input,
and based on certain criteria, returning the value related to the
passed reference.

Compared to other formulas using meta arguments, using the values
belonging to the cells of the meta arguments is a new behavior.

So, for this function to be viable, two things must be done:
- compute the values of the passed meta references (which was not
done until now)
- compute all the values of the cells belonging to the matrix when a
range is passed as a meta reference

This last point (computing all the cell values when a meta range is
passed) implies differentiating between simple meta arguments and
matrix meta arguments in the code. Hence the main purpose of this
commit.

Two other implications of this commit:
- This commit enables vectorization for meta arguments.
- We revised the way arguments were defined in meta functions,
resulting in a complete redefinition for certain functions, such as
COLUMNS and ROWS, which no longer use meta arguments. This change
involved redefining the error type for references whose sheetname
doesn't exist. This also promotes consistency.

Task: 4873384
@laa-odoo laa-odoo force-pushed the master-add-subtotal-formula-laa branch 2 times, most recently from 2e9751b to b63b9c1 Compare August 7, 2025 09:08
import { tokenColors } from "../components/composer/composer/abstract_composer_store";
import { splitReference, toZone } from "../helpers";
import { insertTokenAfterLeftParenthesis } from "../helpers/pivot/pivot_composer_helpers";
import { autoCompleteProviders } from "../registries/auto_completes";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a circular dependency

image


for (let col = left; col <= right; col++) {
const cell = this.getters.getCell({ sheetId, col, row });
if (!cell || !cell.isFormula || !cell.content || !cell.content.includes("SUBTOTAL")) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cell.content is expensive for formulas because it builds the entire formula string every time.
Check cell.compiledFormula.tokens instead

Comment on lines 1423 to 1425
return functionRegistry
.get(subtotalFunctionAggregateByCode[code])
.compute.apply(this, [[evaluatedCellToKeep]]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return functionRegistry
.get(subtotalFunctionAggregateByCode[code])
.compute.apply(this, [[evaluatedCellToKeep]]);
return this[subtotalFunctionAggregateByCode[code]].apply(this, [[evaluatedCellToKeep]]);

Comment on lines 1447 to 1448
const subtotalFunctionCodes = Object.keys(subtotalFunctionAggregateByCode);
if (subtotalFunctionCodes.includes(tokenAtCursor.value)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this only checks 1-9 but not the 10x versions.

return;
}

const proposals: any[] = [];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const proposals: any[] = [];
const proposals: AutoCompleteProposal[] = [];

Comment on lines 1431 to 1432
(fnName: string) => _t("%s (accept hidden cells)", fnName),
(fnName: string) => _t(`%s (doesn't accept hidden cells)`, fnName),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(fnName: string) => _t("%s (accept hidden cells)", fnName),
(fnName: string) => _t(`%s (doesn't accept hidden cells)`, fnName),
(fnName: string) => _t("%s (include manually-hidden rows)", fnName),
(fnName: string) => _t(`%s (exclude manually-hidden rows)`, fnName),

Comment on lines 1454 to 1467
for (let i = 0; i < subtotalFunctionAggregateDescriptions.length; i++) {
for (const functionCode of subtotalFunctionCodes) {
const str = `${i === 1 ? Number(functionCode) + 100 : functionCode}`;
proposals.push({
text: str,
description: subtotalFunctionAggregateDescriptions[i](
subtotalFunctionAggregateByCode[functionCode]
),
htmlContent: [{ value: str, color: tokenColors.NUMBER }],
fuzzySearchKey: str,
alwaysExpanded: true,
});
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like that would be a lot easier to read IMO, with a small helper function codeToProposal

    for (const code of subtotalFunctionCodes) {
      proposals.push(codeToProposal(code, _t("%s (accept hidden cells)", subtotalFunctionAggregateByCode[code])));
    }
    for (const code of subtotalFunctionCodes.map((c) => `${Number(c) + 100}`)) {
      proposals.push(codeToProposal(code, _t("%s (doesn't accept hidden cells)", subtotalFunctionAggregateByCode[code])));
    }

@laa-odoo
Copy link
Collaborator Author

laa-odoo commented Aug 18, 2025

@LucasLefevre your last review will be taken into account in #6929

@laa-odoo laa-odoo force-pushed the master-add-subtotal-formula-laa branch from b63b9c1 to 45b5db5 Compare August 18, 2025 10:13
@laa-odoo laa-odoo force-pushed the master-add-subtotal-formula-laa branch from 45b5db5 to 825beb1 Compare August 18, 2025 10:53
Copy link
Collaborator

@LucasLefevre LucasLefevre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

robodoo r+ rebase-ff

@robodoo
Copy link
Collaborator

robodoo commented Aug 18, 2025

Merge method set to rebase and fast-forward.

robodoo pushed a commit that referenced this pull request Aug 18, 2025
Why this commit ?

We would like to introduce the SUBTOTAL formula:
This formula has the particularity of taking meta arguments as input,
and based on certain criteria, returning the value related to the
passed reference.

Compared to other formulas using meta arguments, using the values
belonging to the cells of the meta arguments is a new behavior.

So, for this function to be viable, two things must be done:
- compute the values of the passed meta references (which was not
done until now)
- compute all the values of the cells belonging to the matrix when a
range is passed as a meta reference

This last point (computing all the cell values when a meta range is
passed) implies differentiating between simple meta arguments and
matrix meta arguments in the code. Hence the main purpose of this
commit.

Two other implications of this commit:
- This commit enables vectorization for meta arguments.
- We revised the way arguments were defined in meta functions,
resulting in a complete redefinition for certain functions, such as
COLUMNS and ROWS, which no longer use meta arguments. This change
involved redefining the error type for references whose sheetname
doesn't exist. This also promotes consistency.

Task: 4873384
Part-of: #6774
Signed-off-by: Lucas Lefèvre (lul) <[email protected]>
robodoo pushed a commit that referenced this pull request Aug 18, 2025
closes #6774

Task: 4873384
Signed-off-by: Lucas Lefèvre (lul) <[email protected]>
@robodoo robodoo added the 18.5 label Aug 18, 2025
@robodoo robodoo closed this Aug 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants