diff --git a/report_xls/__init__.py b/report_xls/__init__.py index aab5a45b..835cd44c 100644 --- a/report_xls/__init__.py +++ b/report_xls/__init__.py @@ -12,7 +12,7 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License diff --git a/report_xls/__openerp__.py b/report_xls/__openerp__.py index c8fea849..5e85adac 100644 --- a/report_xls/__openerp__.py +++ b/report_xls/__openerp__.py @@ -12,7 +12,7 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License @@ -20,24 +20,60 @@ # ############################################################################## { - 'name': 'XLS report engine', - 'version': '0.3', + 'name': 'Excel report engine', + 'version': '0.4', 'license': 'AGPL-3', 'author': 'Noviat', 'website': 'http://www.noviat.com', 'category': 'Reporting', - 'description': """ + 'description': """ +Excel report engine +=================== + +This module adds Excel export capabilities to the standard OpenERP reporting engine. + +Report development +'''''''''''''''''' +In order to create an Excel report you can\n +- define a report of type 'xls' +- pass ``{'xls_export': 1}`` via the context to the report create method + +The ``report_xls`` class contains a number of attributes and methods to facilitate +the creation XLS reports in OpenERP. + +* cell types + + Supported cell types : text, number, boolean, date. + +* cell styles + + The predefined cell style definitions result in a consistent + look and feel of the OpenERP Excel reports. + +* cell formulas + + Cell formulas can be easily added with the help of the ``rowcol_to_cell()`` function which + you can import from the ``utils.py`` module. + +* 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.openerp.com + as example. + +* XLS with multiple sheets + + Download the ``account_journal_report_xls`` module from http://apps.openerp.com as example. + +Development assistance +'''''''''''''''''''''' +Contact info@noviat.com for help with the development of Excel reports in OpenERP, . -This module adds XLS export capabilities to the standard OpenERP reporting engine. - -In order to generate an XLS export you can define a report of type 'xls' or alternatively pass {'xls_export' : 1) via the context to create method of the report. - """, 'depends': ['base'], 'external_dependencies': {'python': ['xlwt']}, - 'demo_xml': [], - 'init_xml': [], - 'update_xml' : [], + 'demo': [], + 'data': [], 'active': False, 'installable': True, } diff --git a/report_xls/report_xls.py b/report_xls/report_xls.py index e8263a2f..5e19c859 100644 --- a/report_xls/report_xls.py +++ b/report_xls/report_xls.py @@ -2,8 +2,8 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# -#Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. +# +# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -12,7 +12,7 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License @@ -23,7 +23,8 @@ import xlwt from xlwt.Style import default_style import cStringIO -import datetime, time +from datetime import datetime +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT import inspect from types import CodeType from openerp.report.report_sxw import * @@ -32,13 +33,15 @@ from openerp.tools.translate import translate, _ import logging _logger = logging.getLogger(__name__) + class AttrDict(dict): def __init__(self, *args, **kwargs): super(AttrDict, self).__init__(*args, **kwargs) self.__dict__ = self + class report_xls(report_sxw): - + xls_types = { 'bool': xlwt.Row.set_cell_boolean, 'date': xlwt.Row.set_cell_date, @@ -53,36 +56,29 @@ class report_xls(report_sxw): } # TO DO: move parameters infra to configurable data - + # header/footer - DT_FORMAT = '%Y-%m-%d %H:%M:%S' + DT_FORMAT = '%Y-%m-%d %H:%M:%S' hf_params = { 'font_size': 8, - 'font_style': 'I', # B: Bold, I: Italic, U: Underline - } - xls_headers = { - 'standard': '' + 'font_style': 'I', # B: Bold, I: Italic, U: Underline } - xls_footers = { - 'standard': ('&L&%(font_size)s&%(font_style)s' + datetime.now().strftime(DT_FORMAT) + - '&R&%(font_size)s&%(font_style)s&P / &N') %hf_params - } - + # styles - _pfc = '26' # default pattern fore_color - _bc = '22' # borders color + _pfc = '26' # default pattern fore_color + _bc = '22' # borders color decimal_format = '#,##0.00' - date_format = 'YYYY-MM-DD' + date_format = 'YYYY-MM-DD' xls_styles = { 'xls_title': 'font: bold true, height 240;', 'bold': 'font: bold true;', 'underline': 'font: underline true;', 'italic': 'font: italic true;', - 'fill': 'pattern: pattern solid, fore_color %s;' %_pfc, - 'fill_blue' : 'pattern: pattern solid, fore_color 27;', - 'fill_grey' : 'pattern: pattern solid, fore_color 22;', - 'borders_all': 'borders: left thin, right thin, top thin, bottom thin, ' \ - 'left_colour %s, right_colour %s, top_colour %s, bottom_colour %s;' %(_bc,_bc,_bc,_bc), + 'fill': 'pattern: pattern solid, fore_color %s;' % _pfc, + 'fill_blue': 'pattern: pattern solid, fore_color 27;', + 'fill_grey': 'pattern: pattern solid, fore_color 22;', + 'borders_all': 'borders: left thin, right thin, top thin, bottom thin, ' + 'left_colour %s, right_colour %s, top_colour %s, bottom_colour %s;' % (_bc, _bc, _bc, _bc), 'left': 'align: horz left;', 'center': 'align: horz center;', 'right': 'align: horz right;', @@ -91,8 +87,8 @@ class report_xls(report_sxw): 'bottom': 'align: vert bottom;', } # TO DO: move parameters supra to configurable data - - def create(self, cr, uid, ids, data, context=None): + + def create(self, cr, uid, ids, data, context=None): self.pool = pooler.get_pool(cr.dbname) self.cr = cr self.uid = uid @@ -105,11 +101,13 @@ class report_xls(report_sxw): if report_xml.report_type == 'xls': return self.create_source_xls(cr, uid, ids, data, context) elif context.get('xls_export'): + self.table = data.get('model') or self.table # use model from 'data' when no ir.actions.report.xml entry return self.create_source_xls(cr, uid, ids, data, context) return super(report_xls, self).create(cr, uid, ids, data, context) def create_source_xls(self, cr, uid, ids, data, context=None): - if not context: context = {} + if not context: + context = {} parser_instance = self.parser(cr, uid, self.name2, context) self.parser_instance = parser_instance objs = self.getObjects(cr, uid, ids, context) @@ -119,15 +117,22 @@ class report_xls(report_sxw): wb = xlwt.Workbook(encoding='utf-8') _p = AttrDict(parser_instance.localcontext) _xs = self.xls_styles + self.xls_headers = { + 'standard': '', + } + self.xls_footers = { + 'standard': ('&L&%(font_size)s&%(font_style)s' + datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT) + + '&R&%(font_size)s&%(font_style)s&P / &N') % self.hf_params, + } self.generate_xls_report(_p, _xs, data, objs, wb) wb.save(n) n.seek(0) - return (n.read(), 'xls') - + return (n.read(), 'xls') + def render(self, wanted, col_specs, rowtype, render_space='empty'): """ - returns 'mako'-rendered col_specs - + returns 'evaluated' col_specs + Input: - wanted: element from the wanted_list - col_specs : cf. specs[1:] documented in xls_row_template method @@ -139,7 +144,7 @@ class report_xls(report_sxw): caller_space = inspect.currentframe().f_back.f_back.f_locals localcontext = self.parser_instance.localcontext render_space.update(caller_space) - render_space.update(localcontext) + render_space.update(localcontext) row = col_specs[wanted][rowtype][:] for i in range(len(row)): if isinstance(row[i], CodeType): @@ -155,9 +160,9 @@ class report_xls(report_sxw): def xls_row_template(self, specs, wanted_list): """ Returns a row template. - + Input : - - 'wanted_list': list of Columns that will be returned in the row_template + - 'wanted_list': list of Columns that will be returned in the row_template - 'specs': list with Column Characteristics 0: Column Name (from wanted_list) 1: Column Colspan @@ -190,14 +195,14 @@ class report_xls(report_sxw): if s_len > 7 and s[7] is not None: c.append(s[7]) else: - c.append(None) + c.append(None) r.append((col, c[1], c)) col += c[1] break if not found: _logger.warn("report_xls.xls_row_template, column '%s' not found in specs", w) return r - + def xls_write_row(self, ws, row_pos, row_data, row_style=default_style, set_column_size=False): r = ws.row(row_pos) for col, size, spec in row_data: @@ -209,9 +214,9 @@ class report_xls(report_sxw): data = report_xls.xls_types_default[spec[3]] if size != 1: if formula: - ws.write_merge(row_pos, row_pos, col, col+size-1, data, style) + ws.write_merge(row_pos, row_pos, col, col + size - 1, data, style) else: - ws.write_merge(row_pos, row_pos, col, col+size-1, data, style) + ws.write_merge(row_pos, row_pos, col, col + size - 1, data, style) else: if formula: ws.write(row_pos, col, formula, style) @@ -220,5 +225,5 @@ class report_xls(report_sxw): if set_column_size: ws.col(col).width = spec[2] * 256 return row_pos + 1 - + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/report_xls/static/src/img/icon.png b/report_xls/static/src/img/icon.png new file mode 100644 index 00000000..b8a2fcdf Binary files /dev/null and b/report_xls/static/src/img/icon.png differ diff --git a/report_xls/utils.py b/report_xls/utils.py index 30ce800d..e4f3d878 100644 --- a/report_xls/utils.py +++ b/report_xls/utils.py @@ -12,17 +12,18 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # ############################################################################## -# + def _render(code): - return compile(code, '', 'eval') + return compile(code, '', 'eval') + def rowcol_to_cell(row, col, row_abs=False, col_abs=False): # Code based upon utils from xlwt distribution @@ -41,9 +42,9 @@ def rowcol_to_cell(row, col, row_abs=False, col_abs=False): else: col_abs = '' if d > 0: - chr1 = chr(ord('A') + d - 1) + chr1 = chr(ord('A') + d - 1) chr2 = chr(ord('A') + m) # Zero index to 1-index return col_abs + chr1 + chr2 + row_abs + str(row + 1) - + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: