diff --git a/mis_builder/models/kpimatrix.py b/mis_builder/models/kpimatrix.py
index 63c706d7e..aa038db5d 100644
--- a/mis_builder/models/kpimatrix.py
+++ b/mis_builder/models/kpimatrix.py
@@ -464,6 +464,41 @@ def iter_subcols(self):
for col in self.iter_cols():
yield from col.iter_subcols()
+ def iter_visible_rows(self):
+ """Iterate rows that must be displayed, in display order.
+
+ yields KpiMatrixRow.
+ """
+ for row in self.iter_rows():
+ if not (
+ (row.style_props.hide_empty and row.is_empty())
+ or row.style_props.hide_always
+ ):
+ yield row
+
+ def iter_cols_visible(self, hide_empty_columns=False):
+ """Iterate columns in display order. If hide_empty_columns is set,
+ columns where all cells are empty (across visible rows) are skipped.
+
+ yields KpiMatrixCol: one for each column or comparison (if visible).
+ """
+ if not hide_empty_columns:
+ yield from self.iter_cols()
+ return
+ visible_rows = list(self.iter_visible_rows())
+ for col in self.iter_cols():
+ if not self._col_is_empty(col, visible_rows):
+ yield col
+
+ def iter_subcols_visible(self, hide_empty_columns=False):
+ """Iterate sub columns in display order, skipping empty columns.
+
+ yields KpiMatrixSubCol: one for each subkpi in each column and
+ comparison (if visible).
+ """
+ for col in self.iter_cols_visible(hide_empty_columns):
+ yield from col.iter_subcols()
+
def _load_account_names(self):
account_ids = set()
for detail_rows in self._detail_rows.values():
@@ -506,9 +541,21 @@ def get_account_name(self, account_id):
self._load_account_names()
return self._account_names[account_id]
- def as_dict(self):
+ def _col_is_empty(self, col, rows):
+ for subcol in col.iter_subcols():
+ for row in rows:
+ cell = subcol.get_cell_for_row(row)
+ if cell and cell.val not in (AccountingNone, None):
+ return False
+ return True
+
+ def as_dict(self, hide_empty_columns=False):
+ visible_cols = list(self.iter_cols_visible(hide_empty_columns))
+ visible_subcols = [
+ subcol for col in visible_cols for subcol in col.iter_subcols()
+ ]
header = [{"cols": []}, {"cols": []}]
- for col in self.iter_cols():
+ for col in visible_cols:
header[0]["cols"].append(
{
"label": col.label,
@@ -526,18 +573,14 @@ def as_dict(self):
)
body = []
- for row in self.iter_rows():
- if (
- row.style_props.hide_empty and row.is_empty()
- ) or row.style_props.hide_always:
- continue
+ for row in self.iter_visible_rows():
row_data = {
"label": row.label,
"description": row.description,
"style": self._style_model.to_css_style(row.style_props),
"cells": [],
}
- for cell in row.iter_cells():
+ for cell in row.iter_cells(subcols=visible_subcols):
if cell is None:
# TODO use subcol style here
row_data["cells"].append({})
diff --git a/mis_builder/models/mis_report_instance.py b/mis_builder/models/mis_report_instance.py
index bbb9268e5..c6c7b83ec 100644
--- a/mis_builder/models/mis_report_instance.py
+++ b/mis_builder/models/mis_report_instance.py
@@ -605,6 +605,10 @@ def _compute_pivot_date(self):
wide_display_by_default = fields.Boolean(
string="Open report in wide mode by default",
)
+ hide_empty_columns = fields.Boolean(
+ string="Hide empty columns",
+ help="Hide columns for which all displayed values are empty.",
+ )
@api.depends("report_id.move_lines_source")
def _compute_widget_search_view_id(self):
@@ -709,6 +713,12 @@ def _inverse_comparison_mode(self):
record.date_from = None
record.date_to = None
+ @api.onchange("comparison_mode")
+ def _onchange_comparison_mode(self):
+ # hiding empty columns only makes sense when comparing columns
+ if not self.comparison_mode:
+ self.hide_empty_columns = False
+
@api.onchange("date_range_id")
def _onchange_date_range(self):
if self.date_range_id:
@@ -901,7 +911,7 @@ def _compute_matrix(self):
def compute(self):
self.ensure_one()
kpi_matrix = self._compute_matrix()
- ret = kpi_matrix.as_dict()
+ ret = kpi_matrix.as_dict(hide_empty_columns=self.hide_empty_columns)
ret["notes"] = self.get_notes_by_cell_id()
return ret
diff --git a/mis_builder/report/mis_report_instance_qweb.xml b/mis_builder/report/mis_report_instance_qweb.xml
index abdfebec2..50f175898 100644
--- a/mis_builder/report/mis_report_instance_qweb.xml
+++ b/mis_builder/report/mis_report_instance_qweb.xml
@@ -19,6 +19,10 @@