From b917bcc8c8ce86d89978f9c9694d6ec29531ad6e Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Thu, 12 Apr 2018 20:30:20 +0200 Subject: [PATCH 01/45] rename module --- report_xlsx_helper/README.rst | 89 +++++ report_xlsx_helper/__init__.py | 2 + report_xlsx_helper/__manifest__.py | 18 + report_xlsx_helper/report/__init__.py | 2 + .../report/abstract_report_xlsx.py | 363 ++++++++++++++++++ .../static/description/icon.png | Bin 0 -> 9455 bytes 6 files changed, 474 insertions(+) create mode 100644 report_xlsx_helper/README.rst create mode 100644 report_xlsx_helper/__init__.py create mode 100644 report_xlsx_helper/__manifest__.py create mode 100644 report_xlsx_helper/report/__init__.py create mode 100644 report_xlsx_helper/report/abstract_report_xlsx.py create mode 100644 report_xlsx_helper/static/description/icon.png diff --git a/report_xlsx_helper/README.rst b/report_xlsx_helper/README.rst new file mode 100644 index 00000000..b6a77100 --- /dev/null +++ b/report_xlsx_helper/README.rst @@ -0,0 +1,89 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: https://www.gnu.org/licenses/agpl + :alt: License: AGPL-3 + +=========================== +Excel report engine helpers +=========================== + +This module provides a set of tools to facilitate the creation of excel reports with format xlsx. +This module offers a similar functional coverage as the 8.0 version of the ``report_xls`` module. + +Usage +===== + +In order to create an Excel report you can: + +- define a report of type 'xlsx' +- pass ``{'xlsx_export': 1}`` via the context to the report create method + +The ``AbstractReportXlsx`` class contains a number of attributes and methods to +facilitate the creation excel reports in Odoo. + +* Cell types + + string, number, boolean, datetime. + +* Cell formats + + The predefined cell formats result in a consistent + look and feel of the Odoo Excel reports. + +* Cell formulas + + Cell formulas can be easily added with the help of the ``_rowcol_to_cell()`` method. + +* Excel templates + + It is possible to define Excel templates which can be adapted + by 'inherited' modules. + Download the ``account_move_line_report_xls`` module + from http://apps.odoo.com as example. + +* Excel with multiple sheets + + Download the ``account_journal_report_xlsx`` module + from http://apps.odoo.com as example. + +Installation +============ + +There is no specific installation procedure for this module. + +Configuration and Usage +======================= + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/143/10.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Contributors +------------ + +* Luc De Meyer + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/report_xlsx_helper/__init__.py b/report_xlsx_helper/__init__.py new file mode 100644 index 00000000..8323e741 --- /dev/null +++ b/report_xlsx_helper/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import report diff --git a/report_xlsx_helper/__manifest__.py b/report_xlsx_helper/__manifest__.py new file mode 100644 index 00000000..8cf9b6b7 --- /dev/null +++ b/report_xlsx_helper/__manifest__.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# Copyright 2009-2018 Noviat. +# 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': '10.0.1.0.0', + 'license': 'AGPL-3', + 'external_dependencies': {'python': ['xlsxwriter']}, + 'depends': [ + 'report_xlsx', + ], + 'installable': True, +} diff --git a/report_xlsx_helper/report/__init__.py b/report_xlsx_helper/report/__init__.py new file mode 100644 index 00000000..efd56120 --- /dev/null +++ b/report_xlsx_helper/report/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import abstract_report_xlsx diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py new file mode 100644 index 00000000..59954aad --- /dev/null +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -0,0 +1,363 @@ +# -*- coding: utf-8 -*- +# Copyright 2009-2018 Noviat. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from datetime import datetime +import re +from types import CodeType +from xlsxwriter.utility import xl_rowcol_to_cell + +from odoo import api, fields, _ +from odoo.addons.report_xlsx.report.report_xlsx import ReportXlsx +from odoo.exceptions import UserError + + +class AbstractReportXlsx(ReportXlsx): + + def create(self, cr, uid, ids, data, context=None): + if context.get('xlsx_export'): + self.env = api.Environment(cr, uid, context) + return self.create_xlsx_report(ids, data, None) + else: + return super(AbstractReportXlsx, self).create( + cr, uid, ids, data, context=context) + + 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 = 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(workbook, ws, ws_params, data, objects) + + def _check_ws_name(self, name, sanitize=True): + 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 = name[:max_chars] + else: + if len(name) > max_chars: + raise UserError(_( + "Programming Error." + "\nExcel Sheet name '%s' should not exceed %s characters." + ) % (name, max_chars)) + special_chars = pattern.findall(name) + if special_chars: + raise UserError(_( + "Programming Error." + "\nExcel Sheet name '%s' contains unsupported special " + "characters: '%s'." + ) % (name, special_chars)) + return name + + def _get_ws_params(self, workbook, data, objects): + """ + Return list of dictionaries with parameters for the + worksheets. + + Keywords: + - 'generate_ws_method': mandatory + - 'ws_name': name of the worksheet + - 'title': title of the worksheet + - 'wanted_list': list of column names + - 'col_specs': cf. XXX + + The 'generate_ws_method' must be present in your report + and contain the logic to generate the content of the worksheet. + """ + return [] + + def _define_formats(self, workbook): + """ + This section contains a number of pre-defined formats. + It is recommended to use these in order to have a + consistent look & feel between your XLSX reports. + """ + + # predefined worksheet headers/footers + hf_params = { + '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.xls_footers = { + 'standard': ( + '&L&%(font_size)s&%(font_style)s' + report_date + + '&R&%(font_size)s&%(font_style)s&P / &N' + ) % hf_params, + } + + 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' + 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}) + + # 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_amount = workbook.add_format( + {'align': 'right', 'num_format': num_format}) + self.format_amount_conditional = workbook.add_format( + {'align': 'right', 'num_format': num_format_conditional}) + self.format_percent = workbook.add_format( + {'align': 'right', 'num_format': pct_format}) + self.format_percent_conditional = workbook.add_format( + {'align': 'right', 'num_format': pct_format_conditional}) + self.format_integer = workbook.add_format( + {'align': 'right', 'num_format': int_format}) + self.format_integer_conditional = workbook.add_format( + {'align': 'right', 'num_format': int_format_conditional}) + self.format_date = workbook.add_format( + {'align': 'left', '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_amount_bold = workbook.add_format( + {'align': 'right', 'bold': True, 'num_format': num_format}) + self.format_amount_bold_conditional = workbook.add_format( + {'align': 'right', 'bold': True, + 'num_format': num_format_conditional}) + self.format_percent_bold = workbook.add_format( + {'align': 'right', 'bold': True, 'num_format': pct_format}) + self.format_percent_bold_conditional = workbook.add_format( + {'align': 'right', 'bold': True, + 'num_format': pct_format_conditional}) + self.format_integer_bold = workbook.add_format( + {'align': 'right', 'bold': True, 'num_format': int_format}) + self.format_integer_bold_conditional = workbook.add_format( + {'align': 'right', 'bold': True, + 'num_format': int_format_conditional}) + self.format_date_bold = workbook.add_format( + {'align': 'left', 'bold': True, 'num_format': date_format}) + + # formats for worksheet table column headers + self.format_theader_yellow = workbook.add_format(theader_yellow) + self.format_theader_yellow_center = workbook.add_format( + dict(theader_yellow, align='center')) + self.format_theader_yellow_right = workbook.add_format( + dict(theader_yellow, align='right')) + self.format_theader_yellow_amount = workbook.add_format( + dict(theader_yellow, num_format=num_format)) + self.format_theader_yellow_amount_conditional = workbook.add_format( + dict(theader_yellow, num_format=num_format_conditional)) + self.format_theader_yellow_percent = workbook.add_format( + dict(theader_yellow, num_format=pct_format)) + self.format_theader_yellow_percent_conditional = workbook.add_format( + dict(theader_yellow, num_format=pct_format_conditional)) + self.format_theader_yellow_integer = workbook.add_format( + dict(theader_yellow, num_format=int_format)) + self.format_theader_yellow_integer_conditional = workbook.add_format( + dict(theader_yellow, num_format=int_format_conditional)) + + self.format_theader_blue = workbook.add_format(theader_blue) + self.format_theader_blue_center = workbook.add_format( + dict(theader_blue, align='center')) + self.format_theader_blue_right = workbook.add_format( + dict(theader_blue, align='right')) + self.format_theader_blue_amount = workbook.add_format( + dict(theader_blue, num_format=num_format)) + self.format_theader_blue_amount_conditional = workbook.add_format( + dict(theader_blue, num_format=num_format_conditional)) + self.format_theader_blue_percent = workbook.add_format( + dict(theader_blue, num_format=pct_format)) + self.format_theader_blue_percent_conditional = workbook.add_format( + dict(theader_blue, num_format=pct_format_conditional)) + self.format_theader_blue_integer = workbook.add_format( + dict(theader_blue, num_format=int_format)) + self.format_theader_blue_integer_conditional = workbook.add_format( + dict(theader_blue, num_format=int_format_conditional)) + + # formats for worksheet table cells + self.format_tleft = workbook.add_format( + dict(border, align='left')) + self.format_tcenter = workbook.add_format( + dict(border, align='center')) + self.format_tright = workbook.add_format( + dict(border, align='right')) + self.format_tamount = workbook.add_format( + dict(border, num_format=num_format)) + self.format_tamount_conditional = workbook.add_format( + dict(border, num_format=num_format_conditional)) + self.format_tpercent = workbook.add_format( + dict(border, num_format=pct_format)) + self.format_tpercent_conditional = workbook.add_format( + dict(border, num_format=pct_format_conditional)) + self.format_tinteger = workbook.add_format( + dict(border, num_format=int_format)) + self.format_tinteger_conditional = workbook.add_format( + dict(border, num_format=int_format_conditional)) + self.format_tdate = workbook.add_format( + dict(border, align='left', num_format=date_format)) + + self.format_tleft_bold = workbook.add_format( + dict(border, align='left', bold=True)) + self.format_tcenter_bold = workbook.add_format( + dict(border, align='center', bold=True)) + self.format_tright_bold = workbook.add_format( + dict(border, align='right', bold=True)) + self.format_tamount_bold = workbook.add_format( + dict(border, bold=True, num_format=num_format)) + self.format_tamount_bold_conditional = workbook.add_format( + dict(border, bold=True, num_format=num_format_conditional)) + self.format_tpercent_bold = workbook.add_format( + dict(border, bold=True, num_format=pct_format)) + self.format_tpercent_bold_conditional = workbook.add_format( + dict(border, bold=True, num_format=pct_format_conditional)) + self.format_tinteger_bold = workbook.add_format( + dict(border, bold=True, num_format=int_format)) + self.format_tinteger_bold_conditional = workbook.add_format( + dict(border, bold=True, num_format=int_format_conditional)) + self.format_tdate_bold = workbook.add_format( + dict(border, align='left', bold=True, num_format=date_format)) + + 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 [] + for pos, col in enumerate(wl): + if col not in col_specs: + raise UserError(_( + "%s - Programming Error: " + "the '%' column is not defined the worksheet " + "column specifications.") + % (__name__, col)) + ws.set_column(pos, pos, col_specs[col]['width']) + + def _write_ws_title(self, ws, row_pos, ws_params, merge_range=False): + """ + Helper function to ensure consistent title formats + troughout all worksheets. + Requires 'title' keyword in ws_params. + """ + title = ws_params.get('title') + if not title: + raise UserError(_( + "%s - Programming Error: " + "the 'title' parameter is mandatory " + "when calling the '_write_ws_title' method.") + % __name__) + if merge_range: + 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) + 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): + """ + 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 [] + pos = 0 + for col in wl: + if col not in col_specs: + raise UserError(_( + "%s - Programming Error: " + "the '%' column is not defined the worksheet " + "column specifications.") + % (__name__, 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_format = default_format + else: + 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 + if not cell_type: + if isinstance(cell_value, basestring): + cell_type = 'string' + elif isinstance(cell_value, (int, float)): + cell_type = 'number' + elif isinstance(cell_value, bool): + cell_type = 'boolean' + elif isinstance(cell_value, datetime): + cell_type = 'datetime' + else: + if not cell_value: + cell_type = 'blank' + else: + msg = _( + "%s, _write_line : programming error " + "detected while processing " + "col_specs_section %s, column %s" + ) % (__name__, col_specs_section, col) + if cell_value: + msg += _(", cellvalue %s") + raise UserError(msg) + colspan = cell_spec.get('colspan') or colspan + args_pos = [row_pos, pos] + args_data = [cell_value] + if cell_format: + args_data.append(cell_format) + if colspan > 1: + args_pos += [row_pos, pos + colspan - 1] + args = args_pos + args_data + ws.merge_range(*args) + else: + ws_method = getattr(ws, 'write_%s' % cell_type) + args = args_pos + args_data + ws_method(*args) + pos += colspan + + return row_pos + 1 + + @staticmethod + def _render(code): + 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 + # 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 + + @staticmethod + def _rowcol_to_cell(row, col, row_abs=False, col_abs=False): + return xl_rowcol_to_cell(row, col, row_abs=row_abs, col_abs=col_abs) diff --git a/report_xlsx_helper/static/description/icon.png b/report_xlsx_helper/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 From 2ab4d6d46bf7c46a13f39f9ec1d6012a37a63844 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sun, 5 Aug 2018 17:24:15 +0200 Subject: [PATCH 02/45] xlsx formats --- report_xlsx_helper/README.rst | 2 +- .../report/abstract_report_xlsx.py | 358 ++++++++++++++---- 2 files changed, 279 insertions(+), 81 deletions(-) diff --git a/report_xlsx_helper/README.rst b/report_xlsx_helper/README.rst index b6a77100..4be0dc36 100644 --- a/report_xlsx_helper/README.rst +++ b/report_xlsx_helper/README.rst @@ -42,7 +42,7 @@ facilitate the creation excel reports in Odoo. * Excel with multiple sheets - Download the ``account_journal_report_xlsx`` module + Download the ``account_asset_management_xls`` module from http://apps.odoo.com as example. Installation diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index 59954aad..f5b30e32 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -72,14 +72,10 @@ class AbstractReportXlsx(ReportXlsx): """ return [] - def _define_formats(self, workbook): + def _define_xls_headers(self, workbook): """ - This section contains a number of pre-defined formats. - It is recommended to use these in order to have a - consistent look & feel between your XLSX reports. + Predefined worksheet headers/footers. """ - - # predefined worksheet headers/footers hf_params = { 'font_size': 8, 'font_style': 'I', # B: Bold, I: Italic, U: Underline @@ -96,6 +92,14 @@ class AbstractReportXlsx(ReportXlsx): ) % hf_params, } + def _define_formats(self, workbook): + """ + This section contains a number of pre-defined formats. + It is recommended to use these in order to have a + consistent look & feel between your XLSX reports. + """ + self._define_xls_headers(workbook) + border_grey = '#D3D3D3' border = {'border': True, 'border_color': border_grey} theader = dict(border, bold=True) @@ -119,20 +123,48 @@ class AbstractReportXlsx(ReportXlsx): 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 = workbook.add_format( + self.format_amount_left = workbook.add_format( + {'align': 'left', 'num_format': num_format}) + self.format_amount_center = workbook.add_format( + {'align': 'center', 'num_format': num_format}) + self.format_amount_right = workbook.add_format( {'align': 'right', 'num_format': num_format}) - self.format_amount_conditional = workbook.add_format( + self.format_amount_conditional_left = workbook.add_format( + {'align': 'left', 'num_format': num_format_conditional}) + self.format_amount_conditional_center = workbook.add_format( + {'align': 'center', 'num_format': num_format_conditional}) + self.format_amount_conditional_right = workbook.add_format( {'align': 'right', 'num_format': num_format_conditional}) - self.format_percent = workbook.add_format( + self.format_percent_left = workbook.add_format( + {'align': 'left', 'num_format': pct_format}) + self.format_percent_center = workbook.add_format( + {'align': 'center', 'num_format': pct_format}) + self.format_percent_right = workbook.add_format( {'align': 'right', 'num_format': pct_format}) - self.format_percent_conditional = workbook.add_format( + self.format_percent_conditional_left = workbook.add_format( + {'align': 'left', 'num_format': pct_format_conditional}) + self.format_percent_conditional_center = workbook.add_format( + {'align': 'center', 'num_format': pct_format_conditional}) + self.format_percent_conditional_right = workbook.add_format( {'align': 'right', 'num_format': pct_format_conditional}) - self.format_integer = workbook.add_format( + self.format_integer_left = workbook.add_format( + {'align': 'left', 'num_format': int_format}) + self.format_integer_center = workbook.add_format( + {'align': 'center', 'num_format': int_format}) + self.format_integer_right = workbook.add_format( {'align': 'right', 'num_format': int_format}) - self.format_integer_conditional = workbook.add_format( + self.format_integer_conditional_left = workbook.add_format( + {'align': 'right', 'num_format': int_format_conditional}) + self.format_integer_conditional_center = workbook.add_format( + {'align': 'center', 'num_format': int_format_conditional}) + self.format_integer_conditional_right = workbook.add_format( {'align': 'right', 'num_format': int_format_conditional}) - self.format_date = workbook.add_format( + self.format_date_left = workbook.add_format( {'align': 'left', 'num_format': date_format}) + self.format_date_center = workbook.add_format( + {'align': 'center', 'num_format': date_format}) + self.format_date_right = workbook.add_format( + {'align': 'right', 'num_format': date_format}) self.format_left_bold = workbook.add_format( {'align': 'left', 'bold': True}) @@ -140,103 +172,269 @@ class AbstractReportXlsx(ReportXlsx): {'align': 'center', 'bold': True}) self.format_right_bold = workbook.add_format( {'align': 'right', 'bold': True}) - self.format_amount_bold = workbook.add_format( + self.format_amount_left_bold = workbook.add_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}) + self.format_amount_right_bold = workbook.add_format( {'align': 'right', 'bold': True, 'num_format': num_format}) - self.format_amount_bold_conditional = workbook.add_format( + self.format_amount_conditional_left_bold = workbook.add_format( + {'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}) + self.format_amount_conditional_right_bold = workbook.add_format( {'align': 'right', 'bold': True, 'num_format': num_format_conditional}) - self.format_percent_bold = workbook.add_format( + self.format_percent_left_bold = workbook.add_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}) + self.format_percent_right_bold = workbook.add_format( {'align': 'right', 'bold': True, 'num_format': pct_format}) - self.format_percent_bold_conditional = workbook.add_format( + self.format_percent_conditional_left_bold = workbook.add_format( + {'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}) + self.format_percent_conditional_right_bold = workbook.add_format( {'align': 'right', 'bold': True, 'num_format': pct_format_conditional}) - self.format_integer_bold = workbook.add_format( + self.format_integer_left_bold = workbook.add_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}) + self.format_integer_right_bold = workbook.add_format( {'align': 'right', 'bold': True, 'num_format': int_format}) - self.format_integer_bold_conditional = workbook.add_format( + self.format_integer_conditional_left_bold = workbook.add_format( + {'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}) + self.format_integer_conditional_right_bold = workbook.add_format( {'align': 'right', 'bold': True, 'num_format': int_format_conditional}) - self.format_date_bold = workbook.add_format( + self.format_date_left_bold = workbook.add_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}) + self.format_date_right_bold = workbook.add_format( + {'align': 'right', 'bold': True, 'num_format': date_format}) # formats for worksheet table column headers - self.format_theader_yellow = workbook.add_format(theader_yellow) + self.format_theader_yellow_left = workbook.add_format(theader_yellow) self.format_theader_yellow_center = workbook.add_format( dict(theader_yellow, align='center')) self.format_theader_yellow_right = workbook.add_format( dict(theader_yellow, align='right')) - self.format_theader_yellow_amount = workbook.add_format( - dict(theader_yellow, num_format=num_format)) - self.format_theader_yellow_amount_conditional = workbook.add_format( - dict(theader_yellow, num_format=num_format_conditional)) - self.format_theader_yellow_percent = workbook.add_format( - dict(theader_yellow, num_format=pct_format)) - self.format_theader_yellow_percent_conditional = workbook.add_format( - dict(theader_yellow, num_format=pct_format_conditional)) - self.format_theader_yellow_integer = workbook.add_format( - dict(theader_yellow, num_format=int_format)) - self.format_theader_yellow_integer_conditional = workbook.add_format( - dict(theader_yellow, num_format=int_format_conditional)) + self.format_theader_yellow_amount_left = workbook.add_format( + 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')) + self.format_theader_yellow_amount_right = workbook.add_format( + 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_percent_left = workbook.add_format( + 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')) + 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')) + self.format_theader_yellow_integer_left = workbook.add_format( + 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')) + 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')) - self.format_theader_blue = workbook.add_format(theader_blue) + self.format_theader_blue_left = workbook.add_format(theader_blue) self.format_theader_blue_center = workbook.add_format( dict(theader_blue, align='center')) self.format_theader_blue_right = workbook.add_format( dict(theader_blue, align='right')) - self.format_theader_blue_amount = workbook.add_format( - dict(theader_blue, num_format=num_format)) - self.format_theader_blue_amount_conditional = workbook.add_format( - dict(theader_blue, num_format=num_format_conditional)) - self.format_theader_blue_percent = workbook.add_format( - dict(theader_blue, num_format=pct_format)) - self.format_theader_blue_percent_conditional = workbook.add_format( - dict(theader_blue, num_format=pct_format_conditional)) - self.format_theader_blue_integer = workbook.add_format( - dict(theader_blue, num_format=int_format)) - self.format_theader_blue_integer_conditional = workbook.add_format( - dict(theader_blue, num_format=int_format_conditional)) + self.format_theader_blue_amount_left = workbook.add_format( + 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')) + 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')) + self.format_theader_blue_percent_left = workbook.add_format( + 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')) + 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')) + self.format_theader_blue_integer_left = workbook.add_format( + 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')) + 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')) # formats for worksheet table cells - self.format_tleft = workbook.add_format( + self.format_tcell_left = workbook.add_format( dict(border, align='left')) - self.format_tcenter = workbook.add_format( + self.format_tcell_center = workbook.add_format( dict(border, align='center')) - self.format_tright = workbook.add_format( + self.format_tcell_right = workbook.add_format( dict(border, align='right')) - self.format_tamount = workbook.add_format( - dict(border, num_format=num_format)) - self.format_tamount_conditional = workbook.add_format( - dict(border, num_format=num_format_conditional)) - self.format_tpercent = workbook.add_format( - dict(border, num_format=pct_format)) - self.format_tpercent_conditional = workbook.add_format( - dict(border, num_format=pct_format_conditional)) - self.format_tinteger = workbook.add_format( - dict(border, num_format=int_format)) - self.format_tinteger_conditional = workbook.add_format( - dict(border, num_format=int_format_conditional)) - self.format_tdate = workbook.add_format( - dict(border, align='left', num_format=date_format)) + self.format_tcell_amount_left = workbook.add_format( + dict(border, num_format=num_format, align='left')) + self.format_tcell_amount_center = workbook.add_format( + dict(border, num_format=num_format, align='center')) + self.format_tcell_amount_right = workbook.add_format( + 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')) + self.format_tcell_amount_conditional_center = workbook.add_format( + 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')) + self.format_tcell_percent_left = workbook.add_format( + dict(border, num_format=pct_format, align='left')) + self.format_tcell_percent_center = workbook.add_format( + dict(border, num_format=pct_format, align='center')) + self.format_tcell_percent_right = workbook.add_format( + 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')) + self.format_tcell_percent_conditional_center = workbook.add_format( + 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')) + self.format_tcell_integer_left = workbook.add_format( + dict(border, num_format=int_format, align='left')) + self.format_tcell_integer_center = workbook.add_format( + dict(border, num_format=int_format, align='center')) + self.format_tcell_integer_right = workbook.add_format( + 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')) + self.format_tcell_integer_conditional_center = workbook.add_format( + 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')) + self.format_tcell_date_left = workbook.add_format( + dict(border, num_format=date_format, align='left')) + self.format_tcell_date_center = workbook.add_format( + dict(border, num_format=date_format, align='center')) + self.format_tcell_date_right = workbook.add_format( + dict(border, num_format=date_format, align='right')) - self.format_tleft_bold = workbook.add_format( + self.format_tcell_left_bold = workbook.add_format( dict(border, align='left', bold=True)) - self.format_tcenter_bold = workbook.add_format( + self.format_tcell_center_bold = workbook.add_format( dict(border, align='center', bold=True)) - self.format_tright_bold = workbook.add_format( + self.format_tcell_right_bold = workbook.add_format( dict(border, align='right', bold=True)) - self.format_tamount_bold = workbook.add_format( - dict(border, bold=True, num_format=num_format)) - self.format_tamount_bold_conditional = workbook.add_format( - dict(border, bold=True, num_format=num_format_conditional)) - self.format_tpercent_bold = workbook.add_format( - dict(border, bold=True, num_format=pct_format)) - self.format_tpercent_bold_conditional = workbook.add_format( - dict(border, bold=True, num_format=pct_format_conditional)) - self.format_tinteger_bold = workbook.add_format( - dict(border, bold=True, num_format=int_format)) - self.format_tinteger_bold_conditional = workbook.add_format( - dict(border, bold=True, num_format=int_format_conditional)) - self.format_tdate_bold = workbook.add_format( - dict(border, align='left', bold=True, num_format=date_format)) + self.format_tcell_amount_left_bold = workbook.add_format( + 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)) + 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)) + self.format_tcell_percent_left_bold = workbook.add_format( + 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)) + 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)) + self.format_tcell_integer_left_bold = workbook.add_format( + 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)) + 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)) + self.format_tcell_date_left_bold = workbook.add_format( + 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)) + self.format_tcell_date_right_bold = workbook.add_format( + dict(border, num_format=date_format, align='right', bold=True)) def _set_column_width(self, ws, ws_params): """ From 44a0be4e8e7e623b34459c0d762d23f49c0b565c Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Thu, 9 Aug 2018 20:43:24 +0200 Subject: [PATCH 03/45] improved error handling --- .../report/abstract_report_xlsx.py | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index f5b30e32..a3731ea5 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -43,14 +43,14 @@ class AbstractReportXlsx(ReportXlsx): else: if len(name) > max_chars: raise UserError(_( - "Programming Error." - "\nExcel Sheet name '%s' should not exceed %s characters." + "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." - "\nExcel Sheet name '%s' contains unsupported special " + "Programming Error:\n\n" + "Excel Sheet name '%s' contains unsupported special " "characters: '%s'." ) % (name, special_chars)) return name @@ -445,10 +445,9 @@ class AbstractReportXlsx(ReportXlsx): for pos, col in enumerate(wl): if col not in col_specs: raise UserError(_( - "%s - Programming Error: " - "the '%' column is not defined the worksheet " - "column specifications.") - % (__name__, col)) + "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): @@ -460,10 +459,9 @@ class AbstractReportXlsx(ReportXlsx): title = ws_params.get('title') if not title: raise UserError(_( - "%s - Programming Error: " - "the 'title' parameter is mandatory " - "when calling the '_write_ws_title' method.") - % __name__) + "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') if wl and len(wl) > 1: @@ -488,10 +486,9 @@ class AbstractReportXlsx(ReportXlsx): for col in wl: if col not in col_specs: raise UserError(_( - "%s - Programming Error: " - "the '%' column is not defined the worksheet " - "column specifications.") - % (__name__, col)) + "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: From b88ed0bd23595596113be74541b87592ba2ea023 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 12:22:33 +0200 Subject: [PATCH 04/45] autodetect boolean type --- report_xlsx_helper/report/abstract_report_xlsx.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index a3731ea5..37fd8ed7 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -502,12 +502,14 @@ class AbstractReportXlsx(ReportXlsx): cell_type = cell_spec.get('type') cell_format = cell_spec.get('format') or default_format if not cell_type: - if isinstance(cell_value, basestring): + # test bool first since isinstance(val, int) returns + # True when type(val) is bool + if isinstance(cell_value, bool): + cell_type = 'boolean' + elif isinstance(cell_value, basestring): cell_type = 'string' - elif isinstance(cell_value, (int, float)): + elif isinstance(cell_value, (int, long, float)): cell_type = 'number' - elif isinstance(cell_value, bool): - cell_type = 'boolean' elif isinstance(cell_value, datetime): cell_type = 'datetime' else: From 900bf468d154a8c7f7d1672ebf704e75955e04df Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 17:18:40 +0200 Subject: [PATCH 05/45] pylint: disable=old-api7-method-defined --- report_xlsx_helper/report/abstract_report_xlsx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index 37fd8ed7..ea8be8c6 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -14,6 +14,7 @@ from odoo.exceptions import UserError class AbstractReportXlsx(ReportXlsx): + # pylint: disable=old-api7-method-defined def create(self, cr, uid, ids, data, context=None): if context.get('xlsx_export'): self.env = api.Environment(cr, uid, context) From 85c9b1a38a938815882c40ab05d727438ca20bdb Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 17:40:57 +0200 Subject: [PATCH 06/45] pylint: disable=old-api7-method-defined --- report_xlsx_helper/report/abstract_report_xlsx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index ea8be8c6..0f5a4527 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -18,6 +18,7 @@ class AbstractReportXlsx(ReportXlsx): def create(self, cr, uid, ids, data, context=None): if context.get('xlsx_export'): self.env = api.Environment(cr, uid, context) + # pylint: disable=old-api7-method-defined return self.create_xlsx_report(ids, data, None) else: return super(AbstractReportXlsx, self).create( From 620af44e4b1a71b0d35628800c7ec56f09a2890b Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 20:15:32 +0200 Subject: [PATCH 07/45] pylint W8112(eval-referenced) --- report_xlsx_helper/report/abstract_report_xlsx.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index 0f5a4527..7a81f9c3 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -18,7 +18,6 @@ class AbstractReportXlsx(ReportXlsx): def create(self, cr, uid, ids, data, context=None): if context.get('xlsx_export'): self.env = api.Environment(cr, uid, context) - # pylint: disable=old-api7-method-defined return self.create_xlsx_report(ids, data, None) else: return super(AbstractReportXlsx, self).create( @@ -555,7 +554,7 @@ class AbstractReportXlsx(ReportXlsx): 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 + return eval(val, render_space) # pylint: disable=W8112 @staticmethod def _rowcol_to_cell(row, col, row_abs=False, col_abs=False): From d2f51564989cd1dd401aa239515f7397d7d52fb6 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 20:29:56 +0200 Subject: [PATCH 08/45] pylint eval-used --- report_xlsx_helper/report/abstract_report_xlsx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index 7a81f9c3..62eaaac0 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/abstract_report_xlsx.py @@ -554,7 +554,7 @@ class AbstractReportXlsx(ReportXlsx): 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=W8112 + return eval(val, render_space) # pylint: disable=W0123,W8112 @staticmethod def _rowcol_to_cell(row, col, row_abs=False, col_abs=False): From 61adba8fc9821575f2ae50dee13953042a25af6c Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sun, 12 Aug 2018 15:17:52 +0200 Subject: [PATCH 09/45] add unit test --- report_xlsx_helper/tests/__init__.py | 3 + .../tests/test_partner_report_xlsx.py | 100 ++++++++++++++++++ .../tests/test_report_xlsx_helper.py | 22 ++++ 3 files changed, 125 insertions(+) create mode 100644 report_xlsx_helper/tests/__init__.py create mode 100644 report_xlsx_helper/tests/test_partner_report_xlsx.py create mode 100644 report_xlsx_helper/tests/test_report_xlsx_helper.py diff --git a/report_xlsx_helper/tests/__init__.py b/report_xlsx_helper/tests/__init__.py new file mode 100644 index 00000000..798b9f69 --- /dev/null +++ b/report_xlsx_helper/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +from . import test_partner_report_xlsx +from . import test_report_xlsx_helper diff --git a/report_xlsx_helper/tests/test_partner_report_xlsx.py b/report_xlsx_helper/tests/test_partner_report_xlsx.py new file mode 100644 index 00000000..4623e4d9 --- /dev/null +++ b/report_xlsx_helper/tests/test_partner_report_xlsx.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# Copyright 2009-2018 Noviat. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.addons.report_xlsx_helper.report.abstract_report_xlsx \ + import AbstractReportXlsx +from odoo.report import report_sxw + + +class TestPartnerReportXlsx(AbstractReportXlsx): + + def _get_ws_params(self, wb, data, partners): + + partner_template = { + '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, + }, + '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': 10, + }, + } + + ws_params = { + '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] + + def _partner_report(self, workbook, ws, ws_params, data, partners): + + ws.set_portrait() + ws.fit_to_pages(1, 0) + 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.freeze_panes(row_pos, 0) + + 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) + customer_formula = 'IF(%s=TRUE;"Y"; "N")' % 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) + + +TestPartnerReportXlsx( + 'report.test.partner.xlsx', + 'res.partner', + parser=report_sxw.rml_parse) diff --git a/report_xlsx_helper/tests/test_report_xlsx_helper.py b/report_xlsx_helper/tests/test_report_xlsx_helper.py new file mode 100644 index 00000000..e5b140a7 --- /dev/null +++ b/report_xlsx_helper/tests/test_report_xlsx_helper.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Copyright 2009-2018 Noviat. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestReportXlsxHelper(TransactionCase): + + def setUp(self): + super(TestReportXlsxHelper, self).setUp() + ctx = {'xlsx_export': True} + self.report = self.env['ir.actions.report.xml'].with_context(ctx) + self.report_name = 'test.partner.xlsx' + p1 = self.env.ref('base.res_partner_1') + p2 = self.env.ref('base.res_partner_2') + self.partners = p1 + p2 + + def test_report_xlsx_helper(self): + report_xls = self.report.render_report( + self.partners.ids, self.report_name, {}) + self.assertEqual(report_xls[1], 'xlsx') From f8d3175e9de1c7998a12d897ed15254c3e2821b9 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Tue, 14 Aug 2018 07:34:01 +0000 Subject: [PATCH 10/45] [UPD] Update report_xlsx_helper.pot --- .../i18n/report_xlsx_helper.pot | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 report_xlsx_helper/i18n/report_xlsx_helper.pot diff --git a/report_xlsx_helper/i18n/report_xlsx_helper.pot b/report_xlsx_helper/i18n/report_xlsx_helper.pot new file mode 100644 index 00000000..81aed537 --- /dev/null +++ b/report_xlsx_helper/i18n/report_xlsx_helper.pot @@ -0,0 +1,67 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * report_xlsx_helper +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:520 +#, python-format +msgid "%s, _write_line : programming error detected while processing col_specs_section %s, column %s" +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:526 +#, python-format +msgid ", cellvalue %s" +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:52 +#, python-format +msgid "Programming Error:\n" +"\n" +"Excel Sheet name '%s' contains unsupported special characters: '%s'." +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:46 +#, python-format +msgid "Programming Error:\n" +"\n" +"Excel Sheet name '%s' should not exceed %s characters." +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:448 +#, python-format +msgid "Programming Error:\n" +"\n" +"The '%s' column is not defined in the worksheet column specifications." +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:489 +#, python-format +msgid "Programming Error:\n" +"\n" +"The '%s' column is not defined the worksheet column specifications." +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:462 +#, python-format +msgid "Programming Error:\n" +"\n" +"The 'title' parameter is mandatory when calling the '_write_ws_title' method." +msgstr "" + From bd1765e81835f6389d42a4e82989e9746cb0c975 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Mon, 24 Sep 2018 17:29:45 +0200 Subject: [PATCH 11/45] [11.0][MIG] report_xlsx_helper: Migration to 11.0 --- report_xlsx_helper/README.rst | 11 ++-- report_xlsx_helper/__init__.py | 3 +- report_xlsx_helper/__manifest__.py | 4 +- report_xlsx_helper/controllers/__init__.py | 1 + report_xlsx_helper/controllers/main.py | 54 +++++++++++++++++++ report_xlsx_helper/models/__init__.py | 1 + .../models/ir_actions_report.py | 21 ++++++++ report_xlsx_helper/readme/CONTRIBUTORS.rst | 1 + report_xlsx_helper/readme/DESCRIPTION.rst | 1 + report_xlsx_helper/readme/INSTALL.rst | 1 + report_xlsx_helper/readme/USAGE.rst | 32 +++++++++++ report_xlsx_helper/report/__init__.py | 4 +- ...report_xlsx.py => report_xlsx_abstract.py} | 20 ++----- .../test_partner_report_xlsx.py | 18 +++---- report_xlsx_helper/tests/__init__.py | 2 - .../tests/test_report_xlsx_helper.py | 13 ++--- 16 files changed, 140 insertions(+), 47 deletions(-) create mode 100644 report_xlsx_helper/controllers/__init__.py create mode 100644 report_xlsx_helper/controllers/main.py create mode 100644 report_xlsx_helper/models/__init__.py create mode 100644 report_xlsx_helper/models/ir_actions_report.py create mode 100644 report_xlsx_helper/readme/CONTRIBUTORS.rst create mode 100644 report_xlsx_helper/readme/DESCRIPTION.rst create mode 100644 report_xlsx_helper/readme/INSTALL.rst create mode 100644 report_xlsx_helper/readme/USAGE.rst rename report_xlsx_helper/report/{abstract_report_xlsx.py => report_xlsx_abstract.py} (97%) rename report_xlsx_helper/{tests => report}/test_partner_report_xlsx.py (87%) diff --git a/report_xlsx_helper/README.rst b/report_xlsx_helper/README.rst index 4be0dc36..142bdfdf 100644 --- a/report_xlsx_helper/README.rst +++ b/report_xlsx_helper/README.rst @@ -7,15 +7,14 @@ Excel report engine helpers =========================== This module provides a set of tools to facilitate the creation of excel reports with format xlsx. -This module offers a similar functional coverage as the 8.0 version of the ``report_xls`` module. Usage ===== -In order to create an Excel report you can: +In order to create an Excel report you can define a report of type 'xlsx' in a static or dynamic way: -- define a report of type 'xlsx' -- pass ``{'xlsx_export': 1}`` via the context to the report create method +* Static syntax: cf. ``account_move_line_report_xls`` for an example. +* Dynamic syntax: cf. ``report_xlsx_helper_demo`` for an example The ``AbstractReportXlsx`` class contains a number of attributes and methods to facilitate the creation excel reports in Odoo. @@ -48,14 +47,14 @@ facilitate the creation excel reports in Odoo. Installation ============ -There is no specific installation procedure for this module. +This module requires report_xlsx version 11.0.1.0.3 or higher. Configuration and Usage ======================= .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/143/10.0 + :target: https://runbot.odoo-community.org/runbot/143/11.0 Bug Tracker =========== diff --git a/report_xlsx_helper/__init__.py b/report_xlsx_helper/__init__.py index 8323e741..9b6fa04e 100644 --- a/report_xlsx_helper/__init__.py +++ b/report_xlsx_helper/__init__.py @@ -1,2 +1,3 @@ -# -*- coding: utf-8 -*- +from . import controllers +from . import models from . import report diff --git a/report_xlsx_helper/__manifest__.py b/report_xlsx_helper/__manifest__.py index 8cf9b6b7..afd22481 100644 --- a/report_xlsx_helper/__manifest__.py +++ b/report_xlsx_helper/__manifest__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2009-2018 Noviat. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -8,9 +7,8 @@ 'Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/reporting-engine', 'category': 'Reporting', - 'version': '10.0.1.0.0', + 'version': '11.0.1.0.0', 'license': 'AGPL-3', - 'external_dependencies': {'python': ['xlsxwriter']}, 'depends': [ 'report_xlsx', ], diff --git a/report_xlsx_helper/controllers/__init__.py b/report_xlsx_helper/controllers/__init__.py new file mode 100644 index 00000000..12a7e529 --- /dev/null +++ b/report_xlsx_helper/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/report_xlsx_helper/controllers/main.py b/report_xlsx_helper/controllers/main.py new file mode 100644 index 00000000..abaf974d --- /dev/null +++ b/report_xlsx_helper/controllers/main.py @@ -0,0 +1,54 @@ +# Copyright 2009-2018 Noviat. +# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). + +import json + +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) + 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: + + 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'): + # 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 + + 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('.', '_') + xlsxhttpheaders = [ + ('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) diff --git a/report_xlsx_helper/models/__init__.py b/report_xlsx_helper/models/__init__.py new file mode 100644 index 00000000..a248cf21 --- /dev/null +++ b/report_xlsx_helper/models/__init__.py @@ -0,0 +1 @@ +from . import ir_actions_report diff --git a/report_xlsx_helper/models/ir_actions_report.py b/report_xlsx_helper/models/ir_actions_report.py new file mode 100644 index 00000000..81db27d0 --- /dev/null +++ b/report_xlsx_helper/models/ir_actions_report.py @@ -0,0 +1,21 @@ +# Copyright 2009-2018 Noviat. +# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). + +from odoo import api, models, _ +from odoo.exceptions import UserError + + +class IrActionsReport(models.Model): + _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']) + report_model = self.env.get(report_model_name) + if report_model is None: + 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/CONTRIBUTORS.rst b/report_xlsx_helper/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..044d1a00 --- /dev/null +++ b/report_xlsx_helper/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Luc De Meyer diff --git a/report_xlsx_helper/readme/DESCRIPTION.rst b/report_xlsx_helper/readme/DESCRIPTION.rst new file mode 100644 index 00000000..f0fc0ee5 --- /dev/null +++ b/report_xlsx_helper/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module provides a set of tools to facilitate the creation of excel reports with format xlsx. \ No newline at end of file diff --git a/report_xlsx_helper/readme/INSTALL.rst b/report_xlsx_helper/readme/INSTALL.rst new file mode 100644 index 00000000..4bcd5532 --- /dev/null +++ b/report_xlsx_helper/readme/INSTALL.rst @@ -0,0 +1 @@ +This module requires report_xlsx version 11.0.1.0.3 or higher. diff --git a/report_xlsx_helper/readme/USAGE.rst b/report_xlsx_helper/readme/USAGE.rst new file mode 100644 index 00000000..6efc211b --- /dev/null +++ b/report_xlsx_helper/readme/USAGE.rst @@ -0,0 +1,32 @@ +In order to create an Excel report you can define a report of type 'xlsx' in a static or dynamic way: + +* Static syntax: cf. ``account_move_line_report_xls`` for an example. +* Dynamic syntax: cf. ``report_xlsx_helper_demo`` for an example + +The ``AbstractReportXlsx`` class contains a number of attributes and methods to +facilitate the creation excel reports in Odoo. + +* Cell types + + string, number, boolean, datetime. + +* Cell formats + + The predefined cell formats result in a consistent + look and feel of the Odoo Excel reports. + +* Cell formulas + + Cell formulas can be easily added with the help of the ``_rowcol_to_cell()`` method. + +* Excel templates + + It is possible to define Excel templates which can be adapted + by 'inherited' modules. + Download the ``account_move_line_report_xls`` module + from http://apps.odoo.com as example. + +* Excel with multiple sheets + + Download the ``account_asset_management_xls`` module + from http://apps.odoo.com as example. diff --git a/report_xlsx_helper/report/__init__.py b/report_xlsx_helper/report/__init__.py index efd56120..3222e9d5 100644 --- a/report_xlsx_helper/report/__init__.py +++ b/report_xlsx_helper/report/__init__.py @@ -1,2 +1,2 @@ -# -*- coding: utf-8 -*- -from . import abstract_report_xlsx +from . import report_xlsx_abstract +from . import test_partner_report_xlsx diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/report_xlsx_abstract.py similarity index 97% rename from report_xlsx_helper/report/abstract_report_xlsx.py rename to report_xlsx_helper/report/report_xlsx_abstract.py index 62eaaac0..b93cf2a4 100644 --- a/report_xlsx_helper/report/abstract_report_xlsx.py +++ b/report_xlsx_helper/report/report_xlsx_abstract.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2009-2018 Noviat. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -7,21 +6,12 @@ import re from types import CodeType from xlsxwriter.utility import xl_rowcol_to_cell -from odoo import api, fields, _ -from odoo.addons.report_xlsx.report.report_xlsx import ReportXlsx +from odoo import fields, models, _ from odoo.exceptions import UserError -class AbstractReportXlsx(ReportXlsx): - - # pylint: disable=old-api7-method-defined - def create(self, cr, uid, ids, data, context=None): - if context.get('xlsx_export'): - self.env = api.Environment(cr, uid, context) - return self.create_xlsx_report(ids, data, None) - else: - return super(AbstractReportXlsx, self).create( - cr, uid, ids, data, context=context) +class ReportXlsxAbstract(models.AbstractModel): + _inherit = 'report.report_xlsx.abstract' def generate_xlsx_report(self, workbook, data, objects): self._define_formats(workbook) @@ -507,9 +497,9 @@ class AbstractReportXlsx(ReportXlsx): # True when type(val) is bool if isinstance(cell_value, bool): cell_type = 'boolean' - elif isinstance(cell_value, basestring): + elif isinstance(cell_value, str): cell_type = 'string' - elif isinstance(cell_value, (int, long, float)): + elif isinstance(cell_value, (int, float)): cell_type = 'number' elif isinstance(cell_value, datetime): cell_type = 'datetime' diff --git a/report_xlsx_helper/tests/test_partner_report_xlsx.py b/report_xlsx_helper/report/test_partner_report_xlsx.py similarity index 87% rename from report_xlsx_helper/tests/test_partner_report_xlsx.py rename to report_xlsx_helper/report/test_partner_report_xlsx.py index 4623e4d9..53196771 100644 --- a/report_xlsx_helper/tests/test_partner_report_xlsx.py +++ b/report_xlsx_helper/report/test_partner_report_xlsx.py @@ -2,12 +2,12 @@ # Copyright 2009-2018 Noviat. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo.addons.report_xlsx_helper.report.abstract_report_xlsx \ - import AbstractReportXlsx -from odoo.report import report_sxw +from odoo import models -class TestPartnerReportXlsx(AbstractReportXlsx): +class TestPartnerXlsx(models.AbstractModel): + _name = 'report.report_xlsx_helper.test_partner_xlsx' + _inherit = 'report.report_xlsx.abstract' def _get_ws_params(self, wb, data, partners): @@ -47,7 +47,7 @@ class TestPartnerReportXlsx(AbstractReportXlsx): 'type': 'formula', 'value': self._render("customer_formula"), }, - 'width': 10, + 'width': 14, }, } @@ -84,7 +84,7 @@ class TestPartnerReportXlsx(AbstractReportXlsx): wl.index('is_customer') is_customer_cell = self._rowcol_to_cell( row_pos, is_customer_pos) - customer_formula = 'IF(%s=TRUE;"Y"; "N")' % is_customer_cell + 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={ @@ -92,9 +92,3 @@ class TestPartnerReportXlsx(AbstractReportXlsx): 'customer_formula': customer_formula, }, default_format=self.format_tcell_left) - - -TestPartnerReportXlsx( - 'report.test.partner.xlsx', - 'res.partner', - parser=report_sxw.rml_parse) diff --git a/report_xlsx_helper/tests/__init__.py b/report_xlsx_helper/tests/__init__.py index 798b9f69..e33d6b90 100644 --- a/report_xlsx_helper/tests/__init__.py +++ b/report_xlsx_helper/tests/__init__.py @@ -1,3 +1 @@ -# -*- coding: utf-8 -*- -from . import test_partner_report_xlsx from . import test_report_xlsx_helper diff --git a/report_xlsx_helper/tests/test_report_xlsx_helper.py b/report_xlsx_helper/tests/test_report_xlsx_helper.py index e5b140a7..059c1243 100644 --- a/report_xlsx_helper/tests/test_report_xlsx_helper.py +++ b/report_xlsx_helper/tests/test_report_xlsx_helper.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright 2009-2018 Noviat. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). @@ -9,14 +8,16 @@ class TestReportXlsxHelper(TransactionCase): def setUp(self): super(TestReportXlsxHelper, self).setUp() - ctx = {'xlsx_export': True} - self.report = self.env['ir.actions.report.xml'].with_context(ctx) - self.report_name = 'test.partner.xlsx' p1 = self.env.ref('base.res_partner_1') p2 = self.env.ref('base.res_partner_2') self.partners = p1 + p2 + ctx = { + '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) def test_report_xlsx_helper(self): - report_xls = self.report.render_report( - self.partners.ids, self.report_name, {}) + report_xls = self.report.render_xlsx(None, None) self.assertEqual(report_xls[1], 'xlsx') From 95f67d8b6438b1ce36e5b279c9a95ba2cb1341ba Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Wed, 26 Sep 2018 16:15:25 +0200 Subject: [PATCH 12/45] add todo --- report_xlsx_helper/report/test_partner_report_xlsx.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/report_xlsx_helper/report/test_partner_report_xlsx.py b/report_xlsx_helper/report/test_partner_report_xlsx.py index 53196771..d7a26362 100644 --- a/report_xlsx_helper/report/test_partner_report_xlsx.py +++ b/report_xlsx_helper/report/test_partner_report_xlsx.py @@ -5,6 +5,10 @@ from odoo import models +# TODO: +# make PR to move this class as well as the report_xlsx test class +# 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' From a77dede3323cad0b651ecc7aad488157d3ad3a7a Mon Sep 17 00:00:00 2001 From: oca-travis Date: Mon, 1 Oct 2018 11:02:56 +0000 Subject: [PATCH 13/45] [UPD] Update report_xlsx_helper.pot --- .../i18n/report_xlsx_helper.pot | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/report_xlsx_helper/i18n/report_xlsx_helper.pot b/report_xlsx_helper/i18n/report_xlsx_helper.pot index 81aed537..3b925844 100644 --- a/report_xlsx_helper/i18n/report_xlsx_helper.pot +++ b/report_xlsx_helper/i18n/report_xlsx_helper.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 10.0\n" +"Project-Id-Version: Odoo Server 11.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: <>\n" "Language-Team: \n" @@ -14,19 +14,40 @@ msgstr "" "Plural-Forms: \n" #. module: report_xlsx_helper -#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:520 +#: code:addons/report_xlsx_helper/models/ir_actions_report.py:19 +#, python-format +msgid "%s model was not found" +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/report_xlsx_abstract.py:510 #, python-format msgid "%s, _write_line : programming error detected while processing col_specs_section %s, column %s" msgstr "" #. module: report_xlsx_helper -#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:526 +#: code:addons/report_xlsx_helper/report/report_xlsx_abstract.py:516 #, python-format msgid ", cellvalue %s" msgstr "" #. module: report_xlsx_helper -#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:52 +#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx_display_name +msgid "Display Name" +msgstr "" + +#. module: report_xlsx_helper +#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx_id +msgid "ID" +msgstr "" + +#. module: report_xlsx_helper +#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx___last_update +msgid "Last Modified on" +msgstr "" + +#. module: report_xlsx_helper +#: code:addons/report_xlsx_helper/report/report_xlsx_abstract.py:42 #, python-format msgid "Programming Error:\n" "\n" @@ -34,7 +55,7 @@ msgid "Programming Error:\n" msgstr "" #. module: report_xlsx_helper -#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:46 +#: code:addons/report_xlsx_helper/report/report_xlsx_abstract.py:36 #, python-format msgid "Programming Error:\n" "\n" @@ -42,7 +63,7 @@ msgid "Programming Error:\n" msgstr "" #. module: report_xlsx_helper -#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:448 +#: code:addons/report_xlsx_helper/report/report_xlsx_abstract.py:438 #, python-format msgid "Programming Error:\n" "\n" @@ -50,7 +71,7 @@ msgid "Programming Error:\n" msgstr "" #. module: report_xlsx_helper -#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:489 +#: code:addons/report_xlsx_helper/report/report_xlsx_abstract.py:479 #, python-format msgid "Programming Error:\n" "\n" @@ -58,10 +79,25 @@ msgid "Programming Error:\n" msgstr "" #. module: report_xlsx_helper -#: code:addons/report_xlsx_helper/report/abstract_report_xlsx.py:462 +#: code:addons/report_xlsx_helper/report/report_xlsx_abstract.py:452 #, python-format msgid "Programming Error:\n" "\n" "The 'title' parameter is mandatory when calling the '_write_ws_title' method." msgstr "" +#. module: report_xlsx_helper +#: model:ir.model,name:report_xlsx_helper.model_ir_actions_report +msgid "ir.actions.report" +msgstr "" + +#. module: report_xlsx_helper +#: model:ir.model,name:report_xlsx_helper.model_report_report_xlsx_abstract +msgid "report.report_xlsx.abstract" +msgstr "" + +#. module: report_xlsx_helper +#: model:ir.model,name:report_xlsx_helper.model_report_report_xlsx_helper_test_partner_xlsx +msgid "report.report_xlsx_helper.test_partner_xlsx" +msgstr "" + From cf9185db0dea9d6caf1ccb312f8bd04903e0f16a Mon Sep 17 00:00:00 2001 From: OCA Git Bot Date: Tue, 2 Oct 2018 05:23:59 +0200 Subject: [PATCH 14/45] [UPD] README.rst --- report_xlsx_helper/README.rst | 84 ++-- .../static/description/index.html | 457 ++++++++++++++++++ 2 files changed, 512 insertions(+), 29 deletions(-) create mode 100644 report_xlsx_helper/static/description/index.html diff --git a/report_xlsx_helper/README.rst b/report_xlsx_helper/README.rst index 142bdfdf..70106b5a 100644 --- a/report_xlsx_helper/README.rst +++ b/report_xlsx_helper/README.rst @@ -1,13 +1,42 @@ -.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png - :target: https://www.gnu.org/licenses/agpl - :alt: License: AGPL-3 - -=========================== -Excel report engine helpers -=========================== +=================== +Report xlsx helpers +=================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github + :target: https://github.com/OCA/reporting-engine/tree/11.0/report_xlsx_helper + :alt: OCA/reporting-engine +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/reporting-engine-11-0/reporting-engine-11-0-report_xlsx_helper + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/143/11.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| This module provides a set of tools to facilitate the creation of excel reports with format xlsx. +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +This module requires report_xlsx version 11.0.1.0.3 or higher. + Usage ===== @@ -44,45 +73,42 @@ facilitate the creation excel reports in Odoo. Download the ``account_asset_management_xls`` module from http://apps.odoo.com as example. -Installation -============ - -This module requires report_xlsx version 11.0.1.0.3 or higher. - -Configuration and Usage -======================= - -.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas - :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/143/11.0 - Bug Tracker =========== -Bugs are tracked on `GitHub Issues -`_. In case of trouble, please -check there if your issue has already been reported. If you spotted it first, -help us smashing it by providing a detailed and welcomed feedback. +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. Credits ======= +Authors +~~~~~~~ + +* Noviat + Contributors ------------- +~~~~~~~~~~~~ * Luc De Meyer -Maintainer ----------- +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. .. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association :target: https://odoo-community.org -This module is maintained by the OCA. - OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit http://odoo-community.org. +This module is part of the `OCA/reporting-engine `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/report_xlsx_helper/static/description/index.html b/report_xlsx_helper/static/description/index.html new file mode 100644 index 00000000..1b69bbab --- /dev/null +++ b/report_xlsx_helper/static/description/index.html @@ -0,0 +1,457 @@ + + + + + + +Report xlsx helpers + + + +
+

Report xlsx helpers

+ + +

Beta License: AGPL-3 OCA/reporting-engine Translate me on Weblate Try me on Runbot

+

This module provides a set of tools to facilitate the creation of excel reports with format xlsx.

+

Table of contents

+ +
+

Installation

+

This module requires report_xlsx version 11.0.1.0.3 or higher.

+
+
+

Usage

+

In order to create an Excel report you can define a report of type ‘xlsx’ in a static or dynamic way:

+
    +
  • Static syntax: cf. account_move_line_report_xls for an example.
  • +
  • Dynamic syntax: cf. report_xlsx_helper_demo for an example
  • +
+

The AbstractReportXlsx class contains a number of attributes and methods to +facilitate the creation excel reports in Odoo.

+
    +
  • Cell types

    +

    string, number, boolean, datetime.

    +
  • +
  • Cell formats

    +

    The predefined cell formats result in a consistent +look and feel of the Odoo Excel reports.

    +
  • +
  • Cell formulas

    +

    Cell formulas can be easily added with the help of the _rowcol_to_cell() method.

    +
  • +
  • Excel templates

    +

    It is possible to define Excel templates which can be adapted +by ‘inherited’ modules. +Download the account_move_line_report_xls module +from http://apps.odoo.com as example.

    +
  • +
  • Excel with multiple sheets

    +

    Download the account_asset_management_xls module +from http://apps.odoo.com as example.

    +
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Noviat
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/reporting-engine project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + From 9d1609aede7508612e0c0456d8e4017b91d76ad0 Mon Sep 17 00:00:00 2001 From: "luc.demeyer@noviat.com" Date: Sun, 4 Nov 2018 10:07:42 +0100 Subject: [PATCH 15/45] [10.0][FIX]fix _render for cell formats --- report_xlsx_helper/report/report_xlsx_abstract.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/report_xlsx_helper/report/report_xlsx_abstract.py b/report_xlsx_helper/report/report_xlsx_abstract.py index b93cf2a4..5b472cb4 100644 --- a/report_xlsx_helper/report/report_xlsx_abstract.py +++ b/report_xlsx_helper/report/report_xlsx_abstract.py @@ -519,6 +519,8 @@ class ReportXlsxAbstract(models.AbstractModel): args_pos = [row_pos, pos] args_data = [cell_value] if cell_format: + if isinstance(cell_format, CodeType): + cell_format = self._eval(cell_format, render_space) args_data.append(cell_format) if colspan > 1: args_pos += [row_pos, pos + colspan - 1] From 01f9f1354066afcae4ef88d082927576f28f2067 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sun, 21 Apr 2019 21:20:48 +0200 Subject: [PATCH 16/45] [MIG] : Migration to 12.0 --- report_xlsx_helper/__manifest__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/report_xlsx_helper/__manifest__.py b/report_xlsx_helper/__manifest__.py index afd22481..0f3027fe 100644 --- a/report_xlsx_helper/__manifest__.py +++ b/report_xlsx_helper/__manifest__.py @@ -1,4 +1,4 @@ -# Copyright 2009-2018 Noviat. +# Copyright 2009-2019 Noviat. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { @@ -7,7 +7,7 @@ 'Odoo Community Association (OCA)', 'website': 'https://github.com/OCA/reporting-engine', 'category': 'Reporting', - 'version': '11.0.1.0.0', + 'version': '12.0.1.0.0', 'license': 'AGPL-3', 'depends': [ 'report_xlsx', From 269488ac7d907de097d3a1129b7e1b1891f7c95c Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 3 Jun 2019 11:17:01 +0000 Subject: [PATCH 17/45] [UPD] README.rst --- report_xlsx_helper/README.rst | 10 +++++----- report_xlsx_helper/static/description/index.html | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/report_xlsx_helper/README.rst b/report_xlsx_helper/README.rst index 70106b5a..fe1b9748 100644 --- a/report_xlsx_helper/README.rst +++ b/report_xlsx_helper/README.rst @@ -14,13 +14,13 @@ Report xlsx helpers :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github - :target: https://github.com/OCA/reporting-engine/tree/11.0/report_xlsx_helper + :target: https://github.com/OCA/reporting-engine/tree/12.0/report_xlsx_helper :alt: OCA/reporting-engine .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/reporting-engine-11-0/reporting-engine-11-0-report_xlsx_helper + :target: https://translation.odoo-community.org/projects/reporting-engine-12-0/reporting-engine-12-0-report_xlsx_helper :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/143/11.0 + :target: https://runbot.odoo-community.org/runbot/143/12.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -79,7 +79,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -109,6 +109,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/reporting-engine `_ project on GitHub. +This module is part of the `OCA/reporting-engine `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/report_xlsx_helper/static/description/index.html b/report_xlsx_helper/static/description/index.html index 1b69bbab..4056d9af 100644 --- a/report_xlsx_helper/static/description/index.html +++ b/report_xlsx_helper/static/description/index.html @@ -367,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/reporting-engine Translate me on Weblate Try me on Runbot

+

Beta License: AGPL-3 OCA/reporting-engine Translate me on Weblate Try me on Runbot

This module provides a set of tools to facilitate the creation of excel reports with format xlsx.

Table of contents

@@ -424,7 +424,7 @@ from http://apps.odoo.

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -448,7 +448,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/reporting-engine project on GitHub.

+

This module is part of the OCA/reporting-engine project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From aa586600c1ceb247c99e64f1ef5a66e15d1a7398 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Mon, 3 Jun 2019 11:55:01 +0000 Subject: [PATCH 18/45] [UPD] Update report_xlsx_helper.pot --- .../i18n/report_xlsx_helper.pot | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/report_xlsx_helper/i18n/report_xlsx_helper.pot b/report_xlsx_helper/i18n/report_xlsx_helper.pot index 3b925844..c1ceba01 100644 --- a/report_xlsx_helper/i18n/report_xlsx_helper.pot +++ b/report_xlsx_helper/i18n/report_xlsx_helper.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 11.0\n" +"Project-Id-Version: Odoo Server 12.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: <>\n" "Language-Team: \n" @@ -32,17 +32,22 @@ msgid ", cellvalue %s" msgstr "" #. module: report_xlsx_helper -#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx_display_name +#: model:ir.model,name:report_xlsx_helper.model_report_report_xlsx_abstract +msgid "Abstract XLSX Report" +msgstr "" + +#. module: report_xlsx_helper +#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx__display_name msgid "Display Name" msgstr "" #. module: report_xlsx_helper -#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx_id +#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx__id msgid "ID" msgstr "" #. module: report_xlsx_helper -#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx___last_update +#: model:ir.model.fields,field_description:report_xlsx_helper.field_report_report_xlsx_helper_test_partner_xlsx____last_update msgid "Last Modified on" msgstr "" @@ -88,12 +93,7 @@ msgstr "" #. module: report_xlsx_helper #: model:ir.model,name:report_xlsx_helper.model_ir_actions_report -msgid "ir.actions.report" -msgstr "" - -#. module: report_xlsx_helper -#: model:ir.model,name:report_xlsx_helper.model_report_report_xlsx_abstract -msgid "report.report_xlsx.abstract" +msgid "Report Action" msgstr "" #. module: report_xlsx_helper From c18dc746497cf598d8db3affe197d83c0d39c178 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 31 Jul 2019 06:50:18 +0000 Subject: [PATCH 19/45] [UPD] README.rst --- report_xlsx_helper/static/description/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/report_xlsx_helper/static/description/index.html b/report_xlsx_helper/static/description/index.html index 4056d9af..97e54d3a 100644 --- a/report_xlsx_helper/static/description/index.html +++ b/report_xlsx_helper/static/description/index.html @@ -3,7 +3,7 @@ - + Report xlsx helpers