diff --git a/report_xlsx_helper/__manifest__.py b/report_xlsx_helper/__manifest__.py index 9886d3b5..cbb828bc 100644 --- a/report_xlsx_helper/__manifest__.py +++ b/report_xlsx_helper/__manifest__.py @@ -2,15 +2,12 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - 'name': 'Report xlsx helpers', - 'author': 'Noviat,' - 'Odoo Community Association (OCA)', - 'website': 'https://github.com/OCA/reporting-engine', - 'category': 'Reporting', - 'version': '12.0.1.1.1', - 'license': 'AGPL-3', - 'depends': [ - 'report_xlsx', - ], - 'installable': True, + "name": "Report xlsx helpers", + "author": "Noviat," "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/reporting-engine", + "category": "Reporting", + "version": "12.0.1.1.1", + "license": "AGPL-3", + "depends": ["report_xlsx"], + "installable": True, } diff --git a/report_xlsx_helper/controllers/main.py b/report_xlsx_helper/controllers/main.py index abaf974d..115832bc 100644 --- a/report_xlsx_helper/controllers/main.py +++ b/report_xlsx_helper/controllers/main.py @@ -3,52 +3,55 @@ import json +from odoo.http import content_disposition, request, route + from odoo.addons.report_xlsx.controllers.main import ReportController -from odoo.http import content_disposition, route, request class ReportController(ReportController): - - @route([ - '/report//', - '/report///', - ], type='http', auth='user', website=True) + @route( + [ + "/report//", + "/report///", + ], + type="http", + auth="user", + website=True, + ) def report_routes(self, reportname, docids=None, converter=None, **data): - report = request.env['ir.actions.report']._get_report_from_name( - reportname) - if converter == 'xlsx' and not report: + report = request.env["ir.actions.report"]._get_report_from_name(reportname) + if converter == "xlsx" and not report: context = dict(request.env.context) if docids: - docids = [int(i) for i in docids.split(',')] - if data.get('options'): - data.update(json.loads(data.pop('options'))) - if data.get('context'): + docids = [int(i) for i in docids.split(",")] + if data.get("options"): + data.update(json.loads(data.pop("options"))) + if data.get("context"): # Ignore 'lang' here, because the context in data is the one # from the webclient *but* if the user explicitely wants to # change the lang, this mechanism overwrites it. - data['context'] = json.loads(data['context']) - if data['context'].get('lang'): - del data['context']['lang'] - context.update(data['context']) - context['report_name'] = reportname + data["context"] = json.loads(data["context"]) + if data["context"].get("lang"): + del data["context"]["lang"] + context.update(data["context"]) + context["report_name"] = reportname - xlsx = report.with_context(context).render_xlsx( - docids, data=data - )[0] - report_file = context.get('report_file') + xlsx = report.with_context(context).render_xlsx(docids, data=data)[0] + report_file = context.get("report_file") if not report_file: - active_model = context.get('active_model', 'export') - report_file = active_model.replace('.', '_') + active_model = context.get("active_model", "export") + report_file = active_model.replace(".", "_") xlsxhttpheaders = [ - ('Content-Type', 'application/vnd.openxmlformats-' - 'officedocument.spreadsheetml.sheet'), - ('Content-Length', len(xlsx)), ( - 'Content-Disposition', - content_disposition(report_file + '.xlsx') - ) + "Content-Type", + "application/vnd.openxmlformats-" + "officedocument.spreadsheetml.sheet", + ), + ("Content-Length", len(xlsx)), + ("Content-Disposition", content_disposition(report_file + ".xlsx")), ] return request.make_response(xlsx, headers=xlsxhttpheaders) return super(ReportController, self).report_routes( - reportname, docids, converter, **data) + reportname, docids, converter, **data + ) diff --git a/report_xlsx_helper/models/ir_actions_report.py b/report_xlsx_helper/models/ir_actions_report.py index 81db27d0..b0a12fd6 100644 --- a/report_xlsx_helper/models/ir_actions_report.py +++ b/report_xlsx_helper/models/ir_actions_report.py @@ -1,21 +1,19 @@ # Copyright 2009-2018 Noviat. # License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). -from odoo import api, models, _ +from odoo import _, api, models from odoo.exceptions import UserError class IrActionsReport(models.Model): - _inherit = 'ir.actions.report' + _inherit = "ir.actions.report" @api.model def render_xlsx(self, docids, data): - if not self and self.env.context.get('report_name'): - report_model_name = 'report.{}'.format( - self.env.context['report_name']) + if not self and self.env.context.get("report_name"): + report_model_name = "report.{}".format(self.env.context["report_name"]) report_model = self.env.get(report_model_name) if report_model is None: - raise UserError( - _('%s model was not found' % report_model_name)) + raise UserError(_("%s model was not found" % report_model_name)) return report_model.create_xlsx_report(docids, data) return super(IrActionsReport, self).render_xlsx(docids, data) diff --git a/report_xlsx_helper/readme/DESCRIPTION.rst b/report_xlsx_helper/readme/DESCRIPTION.rst index f0fc0ee5..4f2b52c1 100644 --- a/report_xlsx_helper/readme/DESCRIPTION.rst +++ b/report_xlsx_helper/readme/DESCRIPTION.rst @@ -1 +1 @@ -This module provides a set of tools to facilitate the creation of excel reports with format xlsx. \ No newline at end of file +This module provides a set of tools to facilitate the creation of excel reports with format xlsx. diff --git a/report_xlsx_helper/report/report_xlsx_abstract.py b/report_xlsx_helper/report/report_xlsx_abstract.py index 7dadc70f..375fca82 100644 --- a/report_xlsx_helper/report/report_xlsx_abstract.py +++ b/report_xlsx_helper/report/report_xlsx_abstract.py @@ -1,49 +1,55 @@ # Copyright 2009-2018 Noviat. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from datetime import datetime, date import re +from datetime import date, datetime from types import CodeType + from xlsxwriter.utility import xl_rowcol_to_cell -from odoo import fields, models, _ +from odoo import _, fields, models from odoo.exceptions import UserError class ReportXlsxAbstract(models.AbstractModel): - _inherit = 'report.report_xlsx.abstract' + _inherit = "report.report_xlsx.abstract" def generate_xlsx_report(self, workbook, data, objects): self._define_formats(workbook) for ws_params in self._get_ws_params(workbook, data, objects): - ws_name = ws_params.get('ws_name') + ws_name = ws_params.get("ws_name") ws_name = self._check_ws_name(ws_name) ws = workbook.add_worksheet(ws_name) - generate_ws_method = getattr( - self, ws_params['generate_ws_method']) + generate_ws_method = getattr(self, ws_params["generate_ws_method"]) generate_ws_method(workbook, ws, ws_params, data, objects) def _check_ws_name(self, name, sanitize=True): - pattern = re.compile(r'[/\\*\[\]:?]') # invalid characters: /\*[]:? + pattern = re.compile(r"[/\\*\[\]:?]") # invalid characters: /\*[]:? max_chars = 31 if sanitize: # we could drop these two lines since a similar # sanitize is done in tools.misc PatchedXlsxWorkbook - name = pattern.sub('', name) + name = pattern.sub("", name) name = name[:max_chars] else: if len(name) > max_chars: - raise UserError(_( - "Programming Error:\n\n" - "Excel Sheet name '%s' should not exceed %s characters." - ) % (name, max_chars)) + raise UserError( + _( + "Programming Error:\n\n" + "Excel Sheet name '%s' should not exceed %s characters." + ) + % (name, max_chars) + ) special_chars = pattern.findall(name) if special_chars: - raise UserError(_( - "Programming Error:\n\n" - "Excel Sheet name '%s' contains unsupported special " - "characters: '%s'." - ) % (name, special_chars)) + raise UserError( + _( + "Programming Error:\n\n" + "Excel Sheet name '%s' contains unsupported special " + "characters: '%s'." + ) + % (name, special_chars) + ) return name def _get_ws_params(self, workbook, data, objects): @@ -68,19 +74,20 @@ class ReportXlsxAbstract(models.AbstractModel): Predefined worksheet headers/footers. """ hf_params = { - 'font_size': 8, - 'font_style': 'I', # B: Bold, I: Italic, U: Underline - } - self.xls_headers = { - 'standard': '' + "font_size": 8, + "font_style": "I", # B: Bold, I: Italic, U: Underline } + self.xls_headers = {"standard": ""} report_date = fields.Datetime.context_timestamp( - self.env.user, datetime.now()).strftime('%Y-%m-%d %H:%M') + self.env.user, datetime.now() + ).strftime("%Y-%m-%d %H:%M") self.xls_footers = { - 'standard': ( - '&L&%(font_size)s&%(font_style)s' + report_date + - '&R&%(font_size)s&%(font_style)s&P / &N' - ) % hf_params, + "standard": ( + "&L&%(font_size)s&%(font_style)s" + + report_date + + "&R&%(font_size)s&%(font_style)s&P / &N" + ) + % hf_params } def _define_formats(self, workbook): @@ -91,355 +98,443 @@ class ReportXlsxAbstract(models.AbstractModel): """ self._define_xls_headers(workbook) - border_grey = '#D3D3D3' - border = {'border': True, 'border_color': border_grey} + border_grey = "#D3D3D3" + border = {"border": True, "border_color": border_grey} theader = dict(border, bold=True) - bg_yellow = '#FFFFCC' - bg_blue = '#CCFFFF' - num_format = '#,##0.00' - num_format_conditional = '{0};[Red]-{0};{0}'.format(num_format) - pct_format = '#,##0.00%' - pct_format_conditional = '{0};[Red]-{0};{0}'.format(pct_format) - int_format = '#,##0' - int_format_conditional = '{0};[Red]-{0};{0}'.format(int_format) - date_format = 'YYYY-MM-DD' + bg_yellow = "#FFFFCC" + bg_blue = "#CCFFFF" + num_format = "#,##0.00" + num_format_conditional = "{0};[Red]-{0};{0}".format(num_format) + pct_format = "#,##0.00%" + pct_format_conditional = "{0};[Red]-{0};{0}".format(pct_format) + int_format = "#,##0" + int_format_conditional = "{0};[Red]-{0};{0}".format(int_format) + date_format = "YYYY-MM-DD" theader_yellow = dict(theader, bg_color=bg_yellow) theader_blue = dict(theader, bg_color=bg_blue) # format for worksheet title - self.format_ws_title = workbook.add_format( - {'bold': True, 'font_size': 14}) + self.format_ws_title = workbook.add_format({"bold": True, "font_size": 14}) # no border formats - self.format_left = workbook.add_format({'align': 'left'}) - self.format_center = workbook.add_format({'align': 'center'}) - self.format_right = workbook.add_format({'align': 'right'}) + self.format_left = workbook.add_format({"align": "left"}) + self.format_center = workbook.add_format({"align": "center"}) + self.format_right = workbook.add_format({"align": "right"}) self.format_amount_left = workbook.add_format( - {'align': 'left', 'num_format': num_format}) + {"align": "left", "num_format": num_format} + ) self.format_amount_center = workbook.add_format( - {'align': 'center', 'num_format': num_format}) + {"align": "center", "num_format": num_format} + ) self.format_amount_right = workbook.add_format( - {'align': 'right', 'num_format': num_format}) + {"align": "right", "num_format": num_format} + ) self.format_amount_conditional_left = workbook.add_format( - {'align': 'left', 'num_format': num_format_conditional}) + {"align": "left", "num_format": num_format_conditional} + ) self.format_amount_conditional_center = workbook.add_format( - {'align': 'center', 'num_format': num_format_conditional}) + {"align": "center", "num_format": num_format_conditional} + ) self.format_amount_conditional_right = workbook.add_format( - {'align': 'right', 'num_format': num_format_conditional}) + {"align": "right", "num_format": num_format_conditional} + ) self.format_percent_left = workbook.add_format( - {'align': 'left', 'num_format': pct_format}) + {"align": "left", "num_format": pct_format} + ) self.format_percent_center = workbook.add_format( - {'align': 'center', 'num_format': pct_format}) + {"align": "center", "num_format": pct_format} + ) self.format_percent_right = workbook.add_format( - {'align': 'right', 'num_format': pct_format}) + {"align": "right", "num_format": pct_format} + ) self.format_percent_conditional_left = workbook.add_format( - {'align': 'left', 'num_format': pct_format_conditional}) + {"align": "left", "num_format": pct_format_conditional} + ) self.format_percent_conditional_center = workbook.add_format( - {'align': 'center', 'num_format': pct_format_conditional}) + {"align": "center", "num_format": pct_format_conditional} + ) self.format_percent_conditional_right = workbook.add_format( - {'align': 'right', 'num_format': pct_format_conditional}) + {"align": "right", "num_format": pct_format_conditional} + ) self.format_integer_left = workbook.add_format( - {'align': 'left', 'num_format': int_format}) + {"align": "left", "num_format": int_format} + ) self.format_integer_center = workbook.add_format( - {'align': 'center', 'num_format': int_format}) + {"align": "center", "num_format": int_format} + ) self.format_integer_right = workbook.add_format( - {'align': 'right', 'num_format': int_format}) + {"align": "right", "num_format": int_format} + ) self.format_integer_conditional_left = workbook.add_format( - {'align': 'right', 'num_format': int_format_conditional}) + {"align": "right", "num_format": int_format_conditional} + ) self.format_integer_conditional_center = workbook.add_format( - {'align': 'center', 'num_format': int_format_conditional}) + {"align": "center", "num_format": int_format_conditional} + ) self.format_integer_conditional_right = workbook.add_format( - {'align': 'right', 'num_format': int_format_conditional}) + {"align": "right", "num_format": int_format_conditional} + ) self.format_date_left = workbook.add_format( - {'align': 'left', 'num_format': date_format}) + {"align": "left", "num_format": date_format} + ) self.format_date_center = workbook.add_format( - {'align': 'center', 'num_format': date_format}) + {"align": "center", "num_format": date_format} + ) self.format_date_right = workbook.add_format( - {'align': 'right', 'num_format': date_format}) + {"align": "right", "num_format": date_format} + ) - self.format_left_bold = workbook.add_format( - {'align': 'left', 'bold': True}) - self.format_center_bold = workbook.add_format( - {'align': 'center', 'bold': True}) - self.format_right_bold = workbook.add_format( - {'align': 'right', 'bold': True}) + self.format_left_bold = workbook.add_format({"align": "left", "bold": True}) + self.format_center_bold = workbook.add_format({"align": "center", "bold": True}) + self.format_right_bold = workbook.add_format({"align": "right", "bold": True}) self.format_amount_left_bold = workbook.add_format( - {'align': 'left', 'bold': True, 'num_format': num_format}) + {"align": "left", "bold": True, "num_format": num_format} + ) self.format_amount_center_bold = workbook.add_format( - {'align': 'center', 'bold': True, 'num_format': num_format}) + {"align": "center", "bold": True, "num_format": num_format} + ) self.format_amount_right_bold = workbook.add_format( - {'align': 'right', 'bold': True, 'num_format': num_format}) + {"align": "right", "bold": True, "num_format": num_format} + ) self.format_amount_conditional_left_bold = workbook.add_format( - {'align': 'left', 'bold': True, - 'num_format': num_format_conditional}) + {"align": "left", "bold": True, "num_format": num_format_conditional} + ) self.format_amount_conditional_center_bold = workbook.add_format( - {'align': 'center', 'bold': True, - 'num_format': num_format_conditional}) + {"align": "center", "bold": True, "num_format": num_format_conditional} + ) self.format_amount_conditional_right_bold = workbook.add_format( - {'align': 'right', 'bold': True, - 'num_format': num_format_conditional}) + {"align": "right", "bold": True, "num_format": num_format_conditional} + ) self.format_percent_left_bold = workbook.add_format( - {'align': 'left', 'bold': True, 'num_format': pct_format}) + {"align": "left", "bold": True, "num_format": pct_format} + ) self.format_percent_center_bold = workbook.add_format( - {'align': 'center', 'bold': True, 'num_format': pct_format}) + {"align": "center", "bold": True, "num_format": pct_format} + ) self.format_percent_right_bold = workbook.add_format( - {'align': 'right', 'bold': True, 'num_format': pct_format}) + {"align": "right", "bold": True, "num_format": pct_format} + ) self.format_percent_conditional_left_bold = workbook.add_format( - {'align': 'left', 'bold': True, - 'num_format': pct_format_conditional}) + {"align": "left", "bold": True, "num_format": pct_format_conditional} + ) self.format_percent_conditional_center_bold = workbook.add_format( - {'align': 'center', 'bold': True, - 'num_format': pct_format_conditional}) + {"align": "center", "bold": True, "num_format": pct_format_conditional} + ) self.format_percent_conditional_right_bold = workbook.add_format( - {'align': 'right', 'bold': True, - 'num_format': pct_format_conditional}) + {"align": "right", "bold": True, "num_format": pct_format_conditional} + ) self.format_integer_left_bold = workbook.add_format( - {'align': 'left', 'bold': True, 'num_format': int_format}) + {"align": "left", "bold": True, "num_format": int_format} + ) self.format_integer_center_bold = workbook.add_format( - {'align': 'center', 'bold': True, 'num_format': int_format}) + {"align": "center", "bold": True, "num_format": int_format} + ) self.format_integer_right_bold = workbook.add_format( - {'align': 'right', 'bold': True, 'num_format': int_format}) + {"align": "right", "bold": True, "num_format": int_format} + ) self.format_integer_conditional_left_bold = workbook.add_format( - {'align': 'left', 'bold': True, - 'num_format': int_format_conditional}) + {"align": "left", "bold": True, "num_format": int_format_conditional} + ) self.format_integer_conditional_center_bold = workbook.add_format( - {'align': 'center', 'bold': True, - 'num_format': int_format_conditional}) + {"align": "center", "bold": True, "num_format": int_format_conditional} + ) self.format_integer_conditional_right_bold = workbook.add_format( - {'align': 'right', 'bold': True, - 'num_format': int_format_conditional}) + {"align": "right", "bold": True, "num_format": int_format_conditional} + ) self.format_date_left_bold = workbook.add_format( - {'align': 'left', 'bold': True, 'num_format': date_format}) + {"align": "left", "bold": True, "num_format": date_format} + ) self.format_date_center_bold = workbook.add_format( - {'align': 'center', 'bold': True, 'num_format': date_format}) + {"align": "center", "bold": True, "num_format": date_format} + ) self.format_date_right_bold = workbook.add_format( - {'align': 'right', 'bold': True, 'num_format': date_format}) + {"align": "right", "bold": True, "num_format": date_format} + ) # formats for worksheet table column headers self.format_theader_yellow_left = workbook.add_format(theader_yellow) self.format_theader_yellow_center = workbook.add_format( - dict(theader_yellow, align='center')) + dict(theader_yellow, align="center") + ) self.format_theader_yellow_right = workbook.add_format( - dict(theader_yellow, align='right')) + dict(theader_yellow, align="right") + ) self.format_theader_yellow_amount_left = workbook.add_format( - dict(theader_yellow, num_format=num_format, align='left')) + dict(theader_yellow, num_format=num_format, align="left") + ) self.format_theader_yellow_amount_center = workbook.add_format( - dict(theader_yellow, num_format=num_format, align='center')) + dict(theader_yellow, num_format=num_format, align="center") + ) self.format_theader_yellow_amount_right = workbook.add_format( - dict(theader_yellow, num_format=num_format, align='right')) + dict(theader_yellow, num_format=num_format, align="right") + ) - self.format_theader_yellow_amount_conditional_left = workbook.\ - add_format(dict(theader_yellow, num_format=num_format_conditional, - align='left')) - self.format_theader_yellow_amount_conditional_center = workbook.\ - add_format(dict(theader_yellow, num_format=num_format_conditional, - align='center')) - self.format_theader_yellow_amount_conditional_right = workbook.\ - add_format(dict(theader_yellow, num_format=num_format_conditional, - align='right')) + self.format_theader_yellow_amount_conditional_left = workbook.add_format( + dict(theader_yellow, num_format=num_format_conditional, align="left") + ) + self.format_theader_yellow_amount_conditional_center = workbook.add_format( + dict(theader_yellow, num_format=num_format_conditional, align="center") + ) + self.format_theader_yellow_amount_conditional_right = workbook.add_format( + dict(theader_yellow, num_format=num_format_conditional, align="right") + ) self.format_theader_yellow_percent_left = workbook.add_format( - dict(theader_yellow, num_format=pct_format, align='left')) + dict(theader_yellow, num_format=pct_format, align="left") + ) self.format_theader_yellow_percent_center = workbook.add_format( - dict(theader_yellow, num_format=pct_format, align='center')) + dict(theader_yellow, num_format=pct_format, align="center") + ) self.format_theader_yellow_percent_right = workbook.add_format( - dict(theader_yellow, num_format=pct_format, align='right')) - self.format_theader_yellow_percent_conditional_left = workbook.\ - add_format(dict(theader_yellow, num_format=pct_format_conditional, - align='left')) - self.format_theader_yellow_percent_conditional_center = workbook.\ - add_format(dict(theader_yellow, num_format=pct_format_conditional, - align='center')) - self.format_theader_yellow_percent_conditional_right = workbook.\ - add_format(dict(theader_yellow, num_format=pct_format_conditional, - align='right')) + dict(theader_yellow, num_format=pct_format, align="right") + ) + self.format_theader_yellow_percent_conditional_left = workbook.add_format( + dict(theader_yellow, num_format=pct_format_conditional, align="left") + ) + self.format_theader_yellow_percent_conditional_center = workbook.add_format( + dict(theader_yellow, num_format=pct_format_conditional, align="center") + ) + self.format_theader_yellow_percent_conditional_right = workbook.add_format( + dict(theader_yellow, num_format=pct_format_conditional, align="right") + ) self.format_theader_yellow_integer_left = workbook.add_format( - dict(theader_yellow, num_format=int_format, align='left')) + dict(theader_yellow, num_format=int_format, align="left") + ) self.format_theader_yellow_integer_center = workbook.add_format( - dict(theader_yellow, num_format=int_format, align='center')) + dict(theader_yellow, num_format=int_format, align="center") + ) self.format_theader_yellow_integer_right = workbook.add_format( - dict(theader_yellow, num_format=int_format, align='right')) - self.format_theader_yellow_integer_conditional_left = workbook.\ - add_format(dict(theader_yellow, num_format=int_format_conditional, - align='left')) - self.format_theader_yellow_integer_conditional_center = workbook.\ - add_format(dict(theader_yellow, num_format=int_format_conditional, - align='center')) - self.format_theader_yellow_integer_conditional_right = workbook.\ - add_format(dict(theader_yellow, num_format=int_format_conditional, - align='right')) + dict(theader_yellow, num_format=int_format, align="right") + ) + self.format_theader_yellow_integer_conditional_left = workbook.add_format( + dict(theader_yellow, num_format=int_format_conditional, align="left") + ) + self.format_theader_yellow_integer_conditional_center = workbook.add_format( + dict(theader_yellow, num_format=int_format_conditional, align="center") + ) + self.format_theader_yellow_integer_conditional_right = workbook.add_format( + dict(theader_yellow, num_format=int_format_conditional, align="right") + ) self.format_theader_blue_left = workbook.add_format(theader_blue) self.format_theader_blue_center = workbook.add_format( - dict(theader_blue, align='center')) + dict(theader_blue, align="center") + ) self.format_theader_blue_right = workbook.add_format( - dict(theader_blue, align='right')) + dict(theader_blue, align="right") + ) self.format_theader_blue_amount_left = workbook.add_format( - dict(theader_blue, num_format=num_format, align='left')) + dict(theader_blue, num_format=num_format, align="left") + ) self.format_theader_blue_amount_center = workbook.add_format( - dict(theader_blue, num_format=num_format, align='center')) + dict(theader_blue, num_format=num_format, align="center") + ) self.format_theader_blue_amount_right = workbook.add_format( - dict(theader_blue, num_format=num_format, align='right')) - self.format_theader_blue_amount_conditional_left = workbook.\ - add_format(dict(theader_blue, num_format=num_format_conditional, - align='left')) - self.format_theader_blue_amount_conditional_center = workbook.\ - add_format(dict(theader_blue, num_format=num_format_conditional, - align='center')) - self.format_theader_blue_amount_conditional_right = workbook.\ - add_format(dict(theader_blue, num_format=num_format_conditional, - align='right')) + dict(theader_blue, num_format=num_format, align="right") + ) + self.format_theader_blue_amount_conditional_left = workbook.add_format( + dict(theader_blue, num_format=num_format_conditional, align="left") + ) + self.format_theader_blue_amount_conditional_center = workbook.add_format( + dict(theader_blue, num_format=num_format_conditional, align="center") + ) + self.format_theader_blue_amount_conditional_right = workbook.add_format( + dict(theader_blue, num_format=num_format_conditional, align="right") + ) self.format_theader_blue_percent_left = workbook.add_format( - dict(theader_blue, num_format=pct_format, align='left')) + dict(theader_blue, num_format=pct_format, align="left") + ) self.format_theader_blue_percent_center = workbook.add_format( - dict(theader_blue, num_format=pct_format, align='center')) + dict(theader_blue, num_format=pct_format, align="center") + ) self.format_theader_blue_percent_right = workbook.add_format( - dict(theader_blue, num_format=pct_format, align='right')) - self.format_theader_blue_percent_conditional_left = workbook.\ - add_format(dict(theader_blue, num_format=pct_format_conditional, - align='left')) - self.format_theader_blue_percent_conditional_center = workbook.\ - add_format(dict(theader_blue, num_format=pct_format_conditional, - align='center')) - self.format_theader_blue_percent_conditional_right = workbook.\ - add_format(dict(theader_blue, num_format=pct_format_conditional, - align='right')) + dict(theader_blue, num_format=pct_format, align="right") + ) + self.format_theader_blue_percent_conditional_left = workbook.add_format( + dict(theader_blue, num_format=pct_format_conditional, align="left") + ) + self.format_theader_blue_percent_conditional_center = workbook.add_format( + dict(theader_blue, num_format=pct_format_conditional, align="center") + ) + self.format_theader_blue_percent_conditional_right = workbook.add_format( + dict(theader_blue, num_format=pct_format_conditional, align="right") + ) self.format_theader_blue_integer_left = workbook.add_format( - dict(theader_blue, num_format=int_format, align='left')) + dict(theader_blue, num_format=int_format, align="left") + ) self.format_theader_blue_integer_center = workbook.add_format( - dict(theader_blue, num_format=int_format, align='center')) + dict(theader_blue, num_format=int_format, align="center") + ) self.format_theader_blue_integer_right = workbook.add_format( - dict(theader_blue, num_format=int_format, align='right')) - self.format_theader_blue_integer_conditional_left = workbook.\ - add_format(dict(theader_blue, num_format=int_format_conditional, - align='left')) - self.format_theader_blue_integer_conditional_center = workbook.\ - add_format(dict(theader_blue, num_format=int_format_conditional, - align='center')) - self.format_theader_blue_integer_conditional_right = workbook.\ - add_format(dict(theader_blue, num_format=int_format_conditional, - align='right')) + dict(theader_blue, num_format=int_format, align="right") + ) + self.format_theader_blue_integer_conditional_left = workbook.add_format( + dict(theader_blue, num_format=int_format_conditional, align="left") + ) + self.format_theader_blue_integer_conditional_center = workbook.add_format( + dict(theader_blue, num_format=int_format_conditional, align="center") + ) + self.format_theader_blue_integer_conditional_right = workbook.add_format( + dict(theader_blue, num_format=int_format_conditional, align="right") + ) # formats for worksheet table cells - self.format_tcell_left = workbook.add_format( - dict(border, align='left')) - self.format_tcell_center = workbook.add_format( - dict(border, align='center')) - self.format_tcell_right = workbook.add_format( - dict(border, align='right')) + self.format_tcell_left = workbook.add_format(dict(border, align="left")) + self.format_tcell_center = workbook.add_format(dict(border, align="center")) + self.format_tcell_right = workbook.add_format(dict(border, align="right")) self.format_tcell_amount_left = workbook.add_format( - dict(border, num_format=num_format, align='left')) + dict(border, num_format=num_format, align="left") + ) self.format_tcell_amount_center = workbook.add_format( - dict(border, num_format=num_format, align='center')) + dict(border, num_format=num_format, align="center") + ) self.format_tcell_amount_right = workbook.add_format( - dict(border, num_format=num_format, align='right')) + dict(border, num_format=num_format, align="right") + ) self.format_tcell_amount_conditional_left = workbook.add_format( - dict(border, num_format=num_format_conditional, align='left')) + dict(border, num_format=num_format_conditional, align="left") + ) self.format_tcell_amount_conditional_center = workbook.add_format( - dict(border, num_format=num_format_conditional, align='center')) + dict(border, num_format=num_format_conditional, align="center") + ) self.format_tcell_amount_conditional_right = workbook.add_format( - dict(border, num_format=num_format_conditional, align='right')) + dict(border, num_format=num_format_conditional, align="right") + ) self.format_tcell_percent_left = workbook.add_format( - dict(border, num_format=pct_format, align='left')) + dict(border, num_format=pct_format, align="left") + ) self.format_tcell_percent_center = workbook.add_format( - dict(border, num_format=pct_format, align='center')) + dict(border, num_format=pct_format, align="center") + ) self.format_tcell_percent_right = workbook.add_format( - dict(border, num_format=pct_format, align='right')) + dict(border, num_format=pct_format, align="right") + ) self.format_tcell_percent_conditional_left = workbook.add_format( - dict(border, num_format=pct_format_conditional, align='left')) + dict(border, num_format=pct_format_conditional, align="left") + ) self.format_tcell_percent_conditional_center = workbook.add_format( - dict(border, num_format=pct_format_conditional, align='center')) + dict(border, num_format=pct_format_conditional, align="center") + ) self.format_tcell_percent_conditional_right = workbook.add_format( - dict(border, num_format=pct_format_conditional, align='right')) + dict(border, num_format=pct_format_conditional, align="right") + ) self.format_tcell_integer_left = workbook.add_format( - dict(border, num_format=int_format, align='left')) + dict(border, num_format=int_format, align="left") + ) self.format_tcell_integer_center = workbook.add_format( - dict(border, num_format=int_format, align='center')) + dict(border, num_format=int_format, align="center") + ) self.format_tcell_integer_right = workbook.add_format( - dict(border, num_format=int_format, align='right')) + dict(border, num_format=int_format, align="right") + ) self.format_tcell_integer_conditional_left = workbook.add_format( - dict(border, num_format=int_format_conditional, align='left')) + dict(border, num_format=int_format_conditional, align="left") + ) self.format_tcell_integer_conditional_center = workbook.add_format( - dict(border, num_format=int_format_conditional, align='center')) + dict(border, num_format=int_format_conditional, align="center") + ) self.format_tcell_integer_conditional_right = workbook.add_format( - dict(border, num_format=int_format_conditional, align='right')) + dict(border, num_format=int_format_conditional, align="right") + ) self.format_tcell_date_left = workbook.add_format( - dict(border, num_format=date_format, align='left')) + dict(border, num_format=date_format, align="left") + ) self.format_tcell_date_center = workbook.add_format( - dict(border, num_format=date_format, align='center')) + dict(border, num_format=date_format, align="center") + ) self.format_tcell_date_right = workbook.add_format( - dict(border, num_format=date_format, align='right')) + dict(border, num_format=date_format, align="right") + ) self.format_tcell_left_bold = workbook.add_format( - dict(border, align='left', bold=True)) + dict(border, align="left", bold=True) + ) self.format_tcell_center_bold = workbook.add_format( - dict(border, align='center', bold=True)) + dict(border, align="center", bold=True) + ) self.format_tcell_right_bold = workbook.add_format( - dict(border, align='right', bold=True)) + dict(border, align="right", bold=True) + ) self.format_tcell_amount_left_bold = workbook.add_format( - dict(border, num_format=num_format, align='left', bold=True)) + dict(border, num_format=num_format, align="left", bold=True) + ) self.format_tcell_amount_center_bold = workbook.add_format( - dict(border, num_format=num_format, align='center', bold=True)) + dict(border, num_format=num_format, align="center", bold=True) + ) self.format_tcell_amount_right_bold = workbook.add_format( - dict(border, num_format=num_format, align='right', bold=True)) - self.format_tcell_amount_conditional_left_bold = workbook.\ - add_format(dict(border, num_format=num_format_conditional, - align='left', bold=True)) - self.format_tcell_amount_conditional_center_bold = workbook.\ - add_format(dict(border, num_format=num_format_conditional, - align='center', bold=True)) - self.format_tcell_amount_conditional_right_bold = workbook.\ - add_format(dict(border, num_format=num_format_conditional, - align='right', bold=True)) + dict(border, num_format=num_format, align="right", bold=True) + ) + self.format_tcell_amount_conditional_left_bold = workbook.add_format( + dict(border, num_format=num_format_conditional, align="left", bold=True) + ) + self.format_tcell_amount_conditional_center_bold = workbook.add_format( + dict(border, num_format=num_format_conditional, align="center", bold=True) + ) + self.format_tcell_amount_conditional_right_bold = workbook.add_format( + dict(border, num_format=num_format_conditional, align="right", bold=True) + ) self.format_tcell_percent_left_bold = workbook.add_format( - dict(border, num_format=pct_format, align='left', bold=True)) + dict(border, num_format=pct_format, align="left", bold=True) + ) self.format_tcell_percent_center_bold = workbook.add_format( - dict(border, num_format=pct_format, align='center', bold=True)) + dict(border, num_format=pct_format, align="center", bold=True) + ) self.format_tcell_percent_right_bold = workbook.add_format( - dict(border, num_format=pct_format, align='right', bold=True)) - self.format_tcell_percent_conditional_left_bold = workbook.\ - add_format(dict(border, num_format=pct_format_conditional, - align='left', bold=True)) - self.format_tcell_percent_conditional_center_bold = workbook.\ - add_format(dict(border, num_format=pct_format_conditional, - align='center', bold=True)) - self.format_tcell_percent_conditional_right_bold = workbook.\ - add_format(dict(border, num_format=pct_format_conditional, - align='right', bold=True)) + dict(border, num_format=pct_format, align="right", bold=True) + ) + self.format_tcell_percent_conditional_left_bold = workbook.add_format( + dict(border, num_format=pct_format_conditional, align="left", bold=True) + ) + self.format_tcell_percent_conditional_center_bold = workbook.add_format( + dict(border, num_format=pct_format_conditional, align="center", bold=True) + ) + self.format_tcell_percent_conditional_right_bold = workbook.add_format( + dict(border, num_format=pct_format_conditional, align="right", bold=True) + ) self.format_tcell_integer_left_bold = workbook.add_format( - dict(border, num_format=int_format, align='left', bold=True)) + dict(border, num_format=int_format, align="left", bold=True) + ) self.format_tcell_integer_center_bold = workbook.add_format( - dict(border, num_format=int_format, align='center', bold=True)) + dict(border, num_format=int_format, align="center", bold=True) + ) self.format_tcell_integer_right_bold = workbook.add_format( - dict(border, num_format=int_format, align='right', bold=True)) - self.format_tcell_integer_conditional_left_bold = workbook.\ - add_format(dict(border, num_format=int_format_conditional, - align='left', bold=True)) - self.format_tcell_integer_conditional_center_bold = workbook.\ - add_format(dict(border, num_format=int_format_conditional, - align='center', bold=True)) - self.format_tcell_integer_conditional_right_bold = workbook.\ - add_format(dict(border, num_format=int_format_conditional, - align='right', bold=True)) + dict(border, num_format=int_format, align="right", bold=True) + ) + self.format_tcell_integer_conditional_left_bold = workbook.add_format( + dict(border, num_format=int_format_conditional, align="left", bold=True) + ) + self.format_tcell_integer_conditional_center_bold = workbook.add_format( + dict(border, num_format=int_format_conditional, align="center", bold=True) + ) + self.format_tcell_integer_conditional_right_bold = workbook.add_format( + dict(border, num_format=int_format_conditional, align="right", bold=True) + ) self.format_tcell_date_left_bold = workbook.add_format( - dict(border, num_format=date_format, align='left', bold=True)) + dict(border, num_format=date_format, align="left", bold=True) + ) self.format_tcell_date_center_bold = workbook.add_format( - dict(border, num_format=date_format, align='center', bold=True)) + dict(border, num_format=date_format, align="center", bold=True) + ) self.format_tcell_date_right_bold = workbook.add_format( - dict(border, num_format=date_format, align='right', bold=True)) + dict(border, num_format=date_format, align="right", bold=True) + ) def _set_column_width(self, ws, ws_params): """ Set width for all columns included in the 'wanted_list'. """ - col_specs = ws_params.get('col_specs') - wl = ws_params.get('wanted_list') or [] + col_specs = ws_params.get("col_specs") + wl = ws_params.get("wanted_list") or [] for pos, col in enumerate(wl): if col not in col_specs: - raise UserError(_( - "Programming Error:\n\n" - "The '%s' column is not defined in the worksheet " - "column specifications.") % col) - ws.set_column(pos, pos, col_specs[col]['width']) + raise UserError( + _( + "Programming Error:\n\n" + "The '%s' column is not defined in the worksheet " + "column specifications." + ) + % col + ) + ws.set_column(pos, pos, col_specs[col]["width"]) def _write_ws_title(self, ws, row_pos, ws_params, merge_range=False): """ @@ -447,69 +542,82 @@ class ReportXlsxAbstract(models.AbstractModel): troughout all worksheets. Requires 'title' keyword in ws_params. """ - title = ws_params.get('title') + title = ws_params.get("title") if not title: - raise UserError(_( - "Programming Error:\n\n" - "The 'title' parameter is mandatory " - "when calling the '_write_ws_title' method.")) + raise UserError( + _( + "Programming Error:\n\n" + "The 'title' parameter is mandatory " + "when calling the '_write_ws_title' method." + ) + ) if merge_range: - wl = ws_params.get('wanted_list') + wl = ws_params.get("wanted_list") if wl and len(wl) > 1: ws.merge_range( - row_pos, 0, row_pos, len(wl) - 1, - title, self.format_ws_title) + row_pos, 0, row_pos, len(wl) - 1, title, self.format_ws_title + ) else: ws.write_string(row_pos, 0, title, self.format_ws_title) return row_pos + 2 - def _write_line(self, ws, row_pos, ws_params, col_specs_section=None, - render_space=None, default_format=None): + def _write_line( + self, + ws, + row_pos, + ws_params, + col_specs_section=None, + render_space=None, + default_format=None, + ): """ Write a line with all columns included in the 'wanted_list'. Use the entry defined by the col_specs_section. An empty cell will be written if no col_specs_section entry for a column. """ - col_specs = ws_params.get('col_specs') - wl = ws_params.get('wanted_list') or [] + col_specs = ws_params.get("col_specs") + wl = ws_params.get("wanted_list") or [] pos = 0 for col in wl: if col not in col_specs: - raise UserError(_( - "Programming Error:\n\n" - "The '%s' column is not defined the worksheet " - "column specifications.") % col) - colspan = col_specs[col].get('colspan') or 1 + raise UserError( + _( + "Programming Error:\n\n" + "The '%s' column is not defined the worksheet " + "column specifications." + ) + % col + ) + colspan = col_specs[col].get("colspan") or 1 cell_spec = col_specs[col].get(col_specs_section) or {} if not cell_spec: cell_value = None - cell_type = 'blank' + cell_type = "blank" cell_format = default_format else: - cell_value = cell_spec.get('value') + cell_value = cell_spec.get("value") if isinstance(cell_value, CodeType): cell_value = self._eval(cell_value, render_space) - cell_type = cell_spec.get('type') - cell_format = cell_spec.get('format') or default_format + cell_type = cell_spec.get("type") + cell_format = cell_spec.get("format") or default_format if not cell_type: # test bool first since isinstance(val, int) returns # True when type(val) is bool if isinstance(cell_value, bool): - cell_type = 'boolean' + cell_type = "boolean" elif isinstance(cell_value, str): - cell_type = 'string' + cell_type = "string" elif isinstance(cell_value, (int, float)): - cell_type = 'number' + cell_type = "number" elif isinstance(cell_value, datetime): - cell_type = 'datetime' + cell_type = "datetime" elif isinstance(cell_value, date): - cell_value = datetime.combine( - cell_value, datetime.min.time()) - cell_type = 'datetime' + cell_value = datetime.combine(cell_value, datetime.min.time()) + cell_type = "datetime" else: if not cell_value: - cell_type = 'blank' + cell_type = "blank" else: msg = _( "%s, _write_line : programming error " @@ -519,7 +627,7 @@ class ReportXlsxAbstract(models.AbstractModel): if cell_value: msg += _(", cellvalue %s") % cell_value raise UserError(msg) - colspan = cell_spec.get('colspan') or colspan + colspan = cell_spec.get("colspan") or colspan args_pos = [row_pos, pos] args_data = [cell_value] if cell_format: @@ -531,7 +639,7 @@ class ReportXlsxAbstract(models.AbstractModel): args = args_pos + args_data ws.merge_range(*args) else: - ws_method = getattr(ws, 'write_%s' % cell_type) + ws_method = getattr(ws, "write_%s" % cell_type) args = args_pos + args_data ws_method(*args) pos += colspan @@ -540,14 +648,14 @@ class ReportXlsxAbstract(models.AbstractModel): @staticmethod def _render(code): - return compile(code, '', 'eval') + return compile(code, "", "eval") @staticmethod def _eval(val, render_space): if not render_space: render_space = {} - if 'datetime' not in render_space: - render_space['datetime'] = datetime + if "datetime" not in render_space: + render_space["datetime"] = datetime # the use of eval is not a security thread as long as the # col_specs template is defined in a python module return eval(val, render_space) # pylint: disable=W0123,W8112 diff --git a/report_xlsx_helper/report/test_partner_report_xlsx.py b/report_xlsx_helper/report/test_partner_report_xlsx.py index 97fa4dab..ad091c8c 100644 --- a/report_xlsx_helper/report/test_partner_report_xlsx.py +++ b/report_xlsx_helper/report/test_partner_report_xlsx.py @@ -9,66 +9,45 @@ from odoo import models # to the tests folder (requires dynamic update Odoo registry when # running unit tests. class TestPartnerXlsx(models.AbstractModel): - _name = 'report.report_xlsx_helper.test_partner_xlsx' - _inherit = 'report.report_xlsx.abstract' + _name = "report.report_xlsx_helper.test_partner_xlsx" + _inherit = "report.report_xlsx.abstract" def _get_ws_params(self, wb, data, partners): partner_template = { - 'name': { - 'header': { - 'value': 'Name', - }, - 'data': { - 'value': self._render("partner.name"), - }, - 'width': 20, + "name": { + "header": {"value": "Name"}, + "data": {"value": self._render("partner.name")}, + "width": 20, }, - 'number_of_contacts': { - 'header': { - 'value': '# Contacts', - }, - 'data': { - 'value': self._render("len(partner.child_ids)"), - }, - 'width': 10, + "number_of_contacts": { + "header": {"value": "# Contacts"}, + "data": {"value": self._render("len(partner.child_ids)")}, + "width": 10, }, - 'is_customer': { - 'header': { - 'value': 'Customer', - }, - 'data': { - 'value': self._render("partner.customer"), - }, - 'width': 10, + "is_customer": { + "header": {"value": "Customer"}, + "data": {"value": self._render("partner.customer")}, + "width": 10, }, - 'is_customer_formula': { - 'header': { - 'value': 'Customer Y/N ?', - }, - 'data': { - 'type': 'formula', - 'value': self._render("customer_formula"), - }, - 'width': 14, + "is_customer_formula": { + "header": {"value": "Customer Y/N ?"}, + "data": {"type": "formula", "value": self._render("customer_formula")}, + "width": 14, }, - 'date': { - 'header': { - 'value': 'Date', - }, - 'data': { - 'value': self._render("partner.date"), - }, - 'width': 13, + "date": { + "header": {"value": "Date"}, + "data": {"value": self._render("partner.date")}, + "width": 13, }, } ws_params = { - 'ws_name': 'Partners', - 'generate_ws_method': '_partner_report', - 'title': 'Partners', - 'wanted_list': [k for k in partner_template], - 'col_specs': partner_template, + "ws_name": "Partners", + "generate_ws_method": "_partner_report", + "title": "Partners", + "wanted_list": [k for k in partner_template], + "col_specs": partner_template, } return [ws_params] @@ -77,30 +56,33 @@ class TestPartnerXlsx(models.AbstractModel): ws.set_portrait() ws.fit_to_pages(1, 0) - ws.set_header(self.xls_headers['standard']) - ws.set_footer(self.xls_footers['standard']) + ws.set_header(self.xls_headers["standard"]) + ws.set_footer(self.xls_footers["standard"]) self._set_column_width(ws, ws_params) row_pos = 0 row_pos = self._write_ws_title(ws, row_pos, ws_params) row_pos = self._write_line( - ws, row_pos, ws_params, col_specs_section='header', - default_format=self.format_theader_yellow_left) + ws, + row_pos, + ws_params, + col_specs_section="header", + default_format=self.format_theader_yellow_left, + ) ws.freeze_panes(row_pos, 0) - wl = ws_params['wanted_list'] + wl = ws_params["wanted_list"] for partner in partners: - is_customer_pos = 'is_customer' in wl and \ - wl.index('is_customer') - is_customer_cell = self._rowcol_to_cell( - row_pos, is_customer_pos) + is_customer_pos = "is_customer" in wl and wl.index("is_customer") + is_customer_cell = self._rowcol_to_cell(row_pos, is_customer_pos) customer_formula = 'IF({},"Y", "N")'.format(is_customer_cell) row_pos = self._write_line( - ws, row_pos, ws_params, col_specs_section='data', - render_space={ - 'partner': partner, - 'customer_formula': customer_formula, - }, - default_format=self.format_tcell_left) + ws, + row_pos, + ws_params, + col_specs_section="data", + render_space={"partner": partner, "customer_formula": customer_formula}, + default_format=self.format_tcell_left, + ) diff --git a/report_xlsx_helper/tests/test_report_xlsx_helper.py b/report_xlsx_helper/tests/test_report_xlsx_helper.py index f2b02ef4..6ffa4125 100644 --- a/report_xlsx_helper/tests/test_report_xlsx_helper.py +++ b/report_xlsx_helper/tests/test_report_xlsx_helper.py @@ -7,22 +7,21 @@ from odoo.tests.common import TransactionCase class TestReportXlsxHelper(TransactionCase): - def setUp(self): super(TestReportXlsxHelper, self).setUp() today = date.today() - p1 = self.env.ref('base.res_partner_1') - p2 = self.env.ref('base.res_partner_2') + p1 = self.env.ref("base.res_partner_1") + p2 = self.env.ref("base.res_partner_2") p1.date = today p2.date = today self.partners = p1 + p2 ctx = { - 'report_name': 'report_xlsx_helper.test_partner_xlsx', - 'active_model': 'res.partner', - 'active_ids': self.partners.ids, + "report_name": "report_xlsx_helper.test_partner_xlsx", + "active_model": "res.partner", + "active_ids": self.partners.ids, } - self.report = self.env['ir.actions.report'].with_context(ctx) + self.report = self.env["ir.actions.report"].with_context(ctx) def test_report_xlsx_helper(self): report_xls = self.report.render_xlsx(None, None) - self.assertEqual(report_xls[1], 'xlsx') + self.assertEqual(report_xls[1], "xlsx")