diff --git a/mis_builder/models/mis_report_instance.py b/mis_builder/models/mis_report_instance.py
index 070ffe1a5..bbb9268e5 100644
--- a/mis_builder/models/mis_report_instance.py
+++ b/mis_builder/models/mis_report_instance.py
@@ -793,7 +793,6 @@ def print_pdf(self):
)
def export_xls(self):
- self.ensure_one()
return self.env.ref("mis_builder.xls_export").report_action(
self, data=dict(dummy=True)
) # required to propagate context
@@ -1023,3 +1022,10 @@ def _compute_user_can_edit_annotation(self):
self.user_can_edit_annotation = self.env.user.has_group(
"mis_builder.group_edit_annotation"
)
+
+ def _get_xlsx_report_name(self):
+ self.ensure_one()
+ return "{} - {}".format(
+ self.name,
+ ", ".join([a.name for a in self.query_company_ids]),
+ )
diff --git a/mis_builder/report/mis_report_instance_xlsx.py b/mis_builder/report/mis_report_instance_xlsx.py
index 26309918e..78e00fc98 100644
--- a/mis_builder/report/mis_report_instance_xlsx.py
+++ b/mis_builder/report/mis_report_instance_xlsx.py
@@ -34,17 +34,18 @@ def _mis_builder_add_annotation(self, sheet, cell, row_pos, col_pos, notes):
if cell and (annotation := notes.get(cell.cell_id, {}).get("text")):
sheet.write_comment(row_pos, col_pos, annotation)
- def generate_xlsx_report(self, workbook, data, objects):
+ def _get_worksheet_name(self, mis_instance):
+ return mis_instance._get_xlsx_report_name()[:31]
+
+ def _generate_xlsx_one_report(self, workbook, mis_instance):
# get the computed result of the report
- matrix = objects._compute_matrix()
- notes = objects.get_notes_by_cell_id()
+ matrix = mis_instance._compute_matrix()
+ notes = mis_instance.get_notes_by_cell_id()
style_obj = self.env["mis.report.style"]
# create worksheet
- report_name = "{} - {}".format(
- objects[0].name, ", ".join([a.name for a in objects[0].query_company_ids])
- )
- sheet = workbook.add_worksheet(report_name[:31])
+ worksheet_name = self._get_worksheet_name(mis_instance)
+ sheet = workbook.add_worksheet(worksheet_name)
row_pos = 0
col_pos = 0
# width of the labels column
@@ -57,13 +58,14 @@ def generate_xlsx_report(self, workbook, data, objects):
header_format = workbook.add_format(
{"bold": True, "align": "center", "bg_color": "#F0EEEE"}
)
+ report_name = mis_instance._get_xlsx_report_name()
sheet.write(row_pos, 0, report_name, bold)
row_pos += 2
# filters
- filter_descriptions = objects.get_filter_descriptions()
+ filter_descriptions = mis_instance.get_filter_descriptions()
if filter_descriptions:
- for filter_description in objects.get_filter_descriptions():
+ for filter_description in mis_instance.get_filter_descriptions():
sheet.write(row_pos, 0, filter_description)
row_pos += 1
row_pos += 1
@@ -88,7 +90,9 @@ def generate_xlsx_report(self, workbook, data, objects):
else:
sheet.write(row_pos, col_pos, label, header_format)
col_width[col_pos] = max(
- col_width[col_pos], len(col.label or ""), len(col.description or "")
+ col_width[col_pos],
+ len(col.label or ""),
+ len(col.description or ""),
)
col_pos += col.colspan
row_pos += 1
@@ -184,3 +188,9 @@ def generate_xlsx_report(self, workbook, data, objects):
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
+
+ def generate_xlsx_report(self, workbook, data, objects):
+ for instance in objects:
+ self._generate_xlsx_one_report(workbook, instance)
diff --git a/mis_builder/report/mis_report_instance_xlsx.xml b/mis_builder/report/mis_report_instance_xlsx.xml
index 6059075b3..d6427196c 100644
--- a/mis_builder/report/mis_report_instance_xlsx.xml
+++ b/mis_builder/report/mis_report_instance_xlsx.xml
@@ -8,4 +8,15 @@
xlsx
mis_report_instance
+
+
+ Export XLS
+
+
+ list
+ code
+
+ action = records.export_xls()
+
+
diff --git a/mis_builder/tests/common.py b/mis_builder/tests/common.py
index 5725cfd6c..f5547da8d 100644
--- a/mis_builder/tests/common.py
+++ b/mis_builder/tests/common.py
@@ -1,10 +1,17 @@
# Copyright 2017 ACSONE SA/NV ()
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
-
import doctest
+import io
+import logging
+
+import openpyxl
+from odoo import api
from odoo.tests import BaseCase, tagged
+_logger = logging.getLogger(__name__)
+_test_logger = logging.getLogger("odoo.tests")
+
def _zip(iter1, iter2):
i = 0
@@ -63,3 +70,35 @@ def load_tests(loader, tests, ignore):
return tests
return load_tests
+
+
+def try_xlsx_report(
+ cr, uid, rname, ids, data=None, context=None, our_module=None, report_type=None
+):
+ """Try to render a report with contents of ids
+
+ This function should also check for common pitfalls of reports.
+
+ this is inspired from the odoo.tools.test_reports.try_report specialiazed to xlsx
+ """
+ if context is None:
+ context = {}
+ _test_logger.info(" - Trying %s.create(%r)", rname, ids)
+
+ env = api.Environment(cr, uid, context)
+
+ res_data, res_format = env["ir.actions.report"]._render(rname, ids, data=data)
+
+ if not res_data:
+ raise ValueError(f"Report {rname} produced an empty result!")
+
+ if res_format == "xlsx":
+ return openpyxl.load_workbook(io.BytesIO(res_data), data_only=True)
+ else:
+ _logger.warning(
+ 'Report %s produced a "%s" chunk, cannot examine it', rname, res_format
+ )
+ return False
+
+ _test_logger.info(" + Report %s produced correctly.", rname)
+ return True
diff --git a/mis_builder/tests/test_mis_report_instance.py b/mis_builder/tests/test_mis_report_instance.py
index 37acf04e7..59bdb2b65 100644
--- a/mis_builder/tests/test_mis_report_instance.py
+++ b/mis_builder/tests/test_mis_report_instance.py
@@ -6,6 +6,7 @@
from ..models.accounting_none import AccountingNone
from ..models.mis_report import TYPE_STR, SubKPITupleLengthError, SubKPIUnknownTypeError
+from .common import try_xlsx_report
class TestMisReportInstance(common.HttpCase):
@@ -355,6 +356,27 @@ def setUp(self):
)
)
+ # create a duplicate of first instance with different period
+ self.report_instance_4 = self.env["mis.report.instance"].create(
+ dict(
+ name="test instance",
+ report_id=self.report.id,
+ company_id=self.env.ref("base.main_company").id,
+ period_ids=[
+ (
+ 0,
+ 0,
+ dict(
+ name="p2",
+ mode="fix",
+ manual_date_from="2015-01-01",
+ manual_date_to="2015-12-31",
+ ),
+ ),
+ ],
+ )
+ )
+
def test_compute(self):
matrix = self.report_instance._compute_matrix()
for row in matrix.iter_rows():
@@ -564,19 +586,25 @@ def test_qweb(self):
def test_xlsx(self):
self.report_instance.export_xls() # get action
- with self.assertLogs("odoo.tools.test_reports", level="WARNING") as log_catcher:
- test_reports.try_report(
- self.env.cr,
- self.env.uid,
- "mis_builder.mis_report_instance_xlsx",
- [self.report_instance.id],
- report_type="xlsx",
- )
- self.assertIn(
- 'Report mis_builder.mis_report_instance_xlsx produced a "xlsx" chunk, '
- "cannot examine it",
- log_catcher.output[0],
+ excel_workbook = try_xlsx_report(
+ self.env.cr,
+ self.env.uid,
+ "mis_builder.mis_report_instance_xlsx",
+ [self.report_instance.id],
+ report_type="xlsx",
+ )
+ self.assertEqual(len(excel_workbook.sheetnames), 1)
+
+ def test_xlsx_multiple_instances(self):
+ self.report_instance.export_xls() # get action
+ excel_workbook = try_xlsx_report(
+ self.env.cr,
+ self.env.uid,
+ "mis_builder.mis_report_instance_xlsx",
+ [self.report_instance.id, self.report_instance_4.id],
+ report_type="xlsx",
)
+ self.assertEqual(len(excel_workbook.sheetnames), 2)
def test_get_kpis_by_account_id(self):
account_ids = (