Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
822 changes: 411 additions & 411 deletions mis_builder/README.rst

Large diffs are not rendered by default.

59 changes: 51 additions & 8 deletions mis_builder/models/kpimatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down Expand Up @@ -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,
Expand All @@ -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({})
Expand Down
12 changes: 11 additions & 1 deletion mis_builder/models/mis_report_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
23 changes: 15 additions & 8 deletions mis_builder/report/mis_report_instance_qweb.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
<t t-set="matrix" t-value="o._compute_matrix()" />
<t t-set="notes" t-value="o.get_notes_by_cell_id()" />
<t t-set="style_obj" t-value="o.env['mis.report.style']" />
<t
t-set="subcols"
t-value="list(matrix.iter_subcols_visible(o.hide_empty_columns))"
/>
<div class="page">
<h3>
<span t-field="o.name" />
Expand All @@ -44,7 +48,10 @@
<div class="mis_thead">
<div class="mis_row">
<div class="mis_cell mis_collabel" />
<t t-foreach="matrix.iter_cols()" t-as="col">
<t
t-foreach="matrix.iter_cols_visible(o.hide_empty_columns)"
t-as="col"
>
<div class="mis_cell mis_collabel">
<t t-out="col.label" />
<t t-if="col.description">
Expand All @@ -63,7 +70,7 @@
</div>
<div class="mis_row">
<div class="mis_cell mis_collabel" />
<t t-foreach="matrix.iter_subcols()" t-as="subcol">
<t t-foreach="subcols" t-as="subcol">
<div class="mis_cell mis_collabel">
<t t-out="subcol.label" />
<t t-if="subcol.description">
Expand All @@ -75,11 +82,8 @@
</div>
</div>
<div class="mis_tbody">
<t t-foreach="matrix.iter_rows()" t-as="row">
<div
t-if="not ((row.style_props.hide_empty and row.is_empty()) or row.style_props.hide_always)"
class="mis_row"
>
<t t-foreach="matrix.iter_visible_rows()" t-as="row">
<div class="mis_row">
<div
t-att-style="style_obj.to_css_style(row.style_props)"
class="mis_cell mis_rowlabel"
Expand All @@ -90,7 +94,10 @@
<t t-out="row.description" />
</t>
</div>
<t t-foreach="row.iter_cells()" t-as="cell">
<t
t-foreach="row.iter_cells(subcols=subcols)"
t-as="cell"
>
<div
t-att-style="cell and style_obj.to_css_style(cell.style_props) or ''"
class="mis_cell mis_amount"
Expand Down
23 changes: 11 additions & 12 deletions mis_builder/report/mis_report_instance_xlsx.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def _generate_xlsx_one_report(self, workbook, mis_instance):
matrix = mis_instance._compute_matrix()
notes = mis_instance.get_notes_by_cell_id()
style_obj = self.env["mis.report.style"]
hide_empty_columns = mis_instance.hide_empty_columns
visible_subcols = list(matrix.iter_subcols_visible(hide_empty_columns))

# create worksheet
worksheet_name = self._get_worksheet_name(mis_instance)
Expand Down Expand Up @@ -73,7 +75,7 @@ def _generate_xlsx_one_report(self, workbook, mis_instance):
# column headers
sheet.write(row_pos, 0, "", header_format)
col_pos = 1
for col in matrix.iter_cols():
for col in matrix.iter_cols_visible(hide_empty_columns):
label = col.label
if col.description:
label += "\n" + col.description
Expand All @@ -100,7 +102,7 @@ def _generate_xlsx_one_report(self, workbook, mis_instance):
# sub column headers
sheet.write(row_pos, 0, "", header_format)
col_pos = 1
for subcol in matrix.iter_subcols():
for subcol in visible_subcols:
label = subcol.label
if subcol.description:
label += "\n" + subcol.description
Expand All @@ -115,11 +117,7 @@ def _generate_xlsx_one_report(self, workbook, mis_instance):
row_pos += 1

# rows
for row in matrix.iter_rows():
if (
row.style_props.hide_empty and row.is_empty()
) or row.style_props.hide_always:
continue
for row in matrix.iter_visible_rows():
row_xlsx_style = style_obj.to_xlsx_style(TYPE_STR, row.style_props)
row_format = workbook.add_format(row_xlsx_style)
col_pos = 0
Expand All @@ -131,7 +129,7 @@ def _generate_xlsx_one_report(self, workbook, mis_instance):
label_col_width = max(
label_col_width, len(row.label or ""), len(row.description or "")
)
for cell in row.iter_cells():
for cell in row.iter_cells(subcols=visible_subcols):
col_pos += 1
self._mis_builder_add_annotation(sheet, cell, row_pos, col_pos, notes)
if not cell or cell.val is AccountingNone:
Expand Down Expand Up @@ -184,10 +182,11 @@ def _generate_xlsx_one_report(self, workbook, mis_instance):

# adjust col widths
sheet.set_column(0, 0, min(label_col_width, MAX_COL_WIDTH) * COL_WIDTH)
data_col_width = min(MAX_COL_WIDTH, max(col_width.values()))
min_col_pos = min(col_width.keys())
max_col_pos = max(col_width.keys())
sheet.set_column(min_col_pos, max_col_pos, data_col_width * COL_WIDTH)
if col_width:
data_col_width = min(MAX_COL_WIDTH, max(col_width.values()))
min_col_pos = min(col_width.keys())
max_col_pos = max(col_width.keys())
sheet.set_column(min_col_pos, max_col_pos, data_col_width * COL_WIDTH)

return sheet

Expand Down
Loading
Loading