From 3be13112415109eecaac730710af5bc93af95362 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Thu, 12 Apr 2018 20:30:20 +0200 Subject: [PATCH 01/53] 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 000000000..b6a771005 --- /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 000000000..8323e7412 --- /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 000000000..8cf9b6b79 --- /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 000000000..efd561209 --- /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 000000000..59954aad5 --- /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 a1dd78c0f0333e60c31877225c4d672f400c7918 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sun, 5 Aug 2018 17:24:15 +0200 Subject: [PATCH 02/53] 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 b6a771005..4be0dc365 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 59954aad5..f5b30e32a 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_date = workbook.add_format( + 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_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_blue = workbook.add_format(theader_blue) + 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_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 74d1c69f49e5577c8488053a1c8cb963d2c63e46 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Thu, 9 Aug 2018 20:43:24 +0200 Subject: [PATCH 03/53] 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 f5b30e32a..a3731ea54 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 b280034a5c3520c4f2f4182a99aea6183c544729 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 12:22:33 +0200 Subject: [PATCH 04/53] autodetect boolean type --- report_xlsx_helper/report/abstract_report_xlsx.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/report_xlsx_helper/report/abstract_report_xlsx.py b/report_xlsx_helper/report/abstract_report_xlsx.py index a3731ea54..37fd8ed72 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): - cell_type = 'string' - elif isinstance(cell_value, (int, float)): - cell_type = 'number' - elif isinstance(cell_value, bool): + # 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, long, float)): + cell_type = 'number' elif isinstance(cell_value, datetime): cell_type = 'datetime' else: From 94bdcea71a9cd156c57e90fffdd8bdca5b0dcb9c Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 17:18:40 +0200 Subject: [PATCH 05/53] 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 37fd8ed72..ea8be8c67 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 7ea45e8d41b26bd19538bb4966e892f921598215 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 17:40:57 +0200 Subject: [PATCH 06/53] 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 ea8be8c67..0f5a45270 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 379ff0a491dbce47d4b252585c033f140f323487 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 20:15:32 +0200 Subject: [PATCH 07/53] 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 0f5a45270..7a81f9c31 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 490e4df5b52ea1421acbd1a584a1bc4023561da4 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Fri, 10 Aug 2018 20:29:56 +0200 Subject: [PATCH 08/53] 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 7a81f9c31..62eaaac0c 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 7066288d0e3770e2e11038e2c0f6d7533618c2b7 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sun, 12 Aug 2018 15:17:52 +0200 Subject: [PATCH 09/53] 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 000000000..798b9f69f --- /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 000000000..4623e4d94 --- /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 000000000..e5b140a70 --- /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 28ecbcfefac3b4fd4d47d783a904aaa0099bcc11 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Tue, 14 Aug 2018 07:34:01 +0000 Subject: [PATCH 10/53] [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 000000000..81aed5373 --- /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 3d39810a78047bfe14ac3e85e773894e3d57d4c1 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Mon, 24 Sep 2018 17:29:45 +0200 Subject: [PATCH 11/53] [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 4be0dc365..142bdfdf2 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 8323e7412..9b6fa04ee 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 8cf9b6b79..afd22481d 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 000000000..12a7e529b --- /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 000000000..abaf974d2 --- /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 000000000..a248cf216 --- /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 000000000..81db27d04 --- /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 000000000..044d1a001 --- /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 000000000..f0fc0ee53 --- /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 000000000..4bcd55325 --- /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 000000000..6efc211b4 --- /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 efd561209..3222e9d5c 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 62eaaac0c..b93cf2a4f 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 4623e4d94..531967715 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 798b9f69f..e33d6b905 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 e5b140a70..059c12430 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 1a9c9f91e782a628c432588584930e8fe913313c Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Wed, 26 Sep 2018 16:15:25 +0200 Subject: [PATCH 12/53] 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 531967715..d7a263624 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 48472ae23e35cac6ef6219cee03405cf2cc3d155 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Mon, 1 Oct 2018 11:02:56 +0000 Subject: [PATCH 13/53] [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 81aed5373..3b925844e 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 c411d53edc22840fdb127edff1abafecb74a9811 Mon Sep 17 00:00:00 2001 From: OCA Git Bot Date: Tue, 2 Oct 2018 05:23:59 +0200 Subject: [PATCH 14/53] [UPD] README.rst --- report_xlsx_helper/README.rst | 82 ++-- .../static/description/index.html | 457 ++++++++++++++++++ 2 files changed, 511 insertions(+), 28 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 142bdfdf2..70106b5ae 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 +=================== +Report xlsx helpers +=================== -=========================== -Excel report engine 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 000000000..1b69bbaba --- /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 3bca944bb3525b99e208686f0b831cdee356233b Mon Sep 17 00:00:00 2001 From: "luc.demeyer@noviat.com" Date: Sun, 4 Nov 2018 10:07:42 +0100 Subject: [PATCH 15/53] [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 b93cf2a4f..5b472cb4e 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 94bc244665e216937c9a9b6f311f07001ecd8d6c Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Sun, 21 Apr 2019 21:20:48 +0200 Subject: [PATCH 16/53] [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 afd22481d..0f3027fed 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 16e967f3e6c5e6e901d979799f7122c16afb9785 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Mon, 3 Jun 2019 11:17:01 +0000 Subject: [PATCH 17/53] [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 70106b5ae..fe1b9748c 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 1b69bbaba..4056d9afb 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 b71adccbfa9f9195a2fd2b2fa039308fa61d57d1 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Mon, 3 Jun 2019 11:55:01 +0000 Subject: [PATCH 18/53] [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 3b925844e..c1ceba014 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 81d919a415b0f88998db18be3dddc4c2e82e6a52 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 31 Jul 2019 06:50:18 +0000 Subject: [PATCH 19/53] [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 4056d9afb..97e54d3a3 100644 --- a/report_xlsx_helper/static/description/index.html +++ b/report_xlsx_helper/static/description/index.html @@ -3,7 +3,7 @@ - + Report xlsx helpers