Merge lp:~luc-demeyer/openerp-reporting-engines/datetime-fix-report_xls into lp:openerp-reporting-engines

Proposed by Luc De Meyer (Noviat)
Status: Merged
Merged at revision: 3
Proposed branch: lp:~luc-demeyer/openerp-reporting-engines/datetime-fix-report_xls
Merge into: lp:openerp-reporting-engines
Diff against target: 351 lines (+100/-58)
4 files modified
report_xls/__init__.py (+1/-1)
report_xls/__openerp__.py (+48/-12)
report_xls/report_xls.py (+45/-40)
report_xls/utils.py (+6/-5)
To merge this branch: bzr merge lp:~luc-demeyer/openerp-reporting-engines/datetime-fix-report_xls
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp Approve
Pedro Manuel Baeza code review Approve
Joël Grand-Guillaume @ camptocamp code review, no tests Approve
Review via email: mp+200604@code.launchpad.net

Description of the change

style & documentation refresh
xls footer datetime fix

To post a comment you must log in.
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

Hi,

Thanks for this cleanup, very much appreciated.

LGTM,

Regards,

review: Approve (code review, no tests)
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

LGTM

review: Approve (code review)
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'report_xls/__init__.py'
--- report_xls/__init__.py 2013-11-15 15:56:47 +0000
+++ report_xls/__init__.py 2014-01-06 22:32:08 +0000
@@ -12,7 +12,7 @@
12#12#
13# This program is distributed in the hope that it will be useful,13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.16# GNU Affero General Public License for more details.
17#17#
18# You should have received a copy of the GNU Affero General Public License18# You should have received a copy of the GNU Affero General Public License
1919
=== modified file 'report_xls/__openerp__.py'
--- report_xls/__openerp__.py 2013-11-15 15:56:47 +0000
+++ report_xls/__openerp__.py 2014-01-06 22:32:08 +0000
@@ -12,7 +12,7 @@
12#12#
13# This program is distributed in the hope that it will be useful,13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.16# GNU Affero General Public License for more details.
17#17#
18# You should have received a copy of the GNU Affero General Public License18# You should have received a copy of the GNU Affero General Public License
@@ -20,24 +20,60 @@
20#20#
21##############################################################################21##############################################################################
22{22{
23 'name': 'XLS report engine',23 'name': 'Excel report engine',
24 'version': '0.3',24 'version': '0.4',
25 'license': 'AGPL-3',25 'license': 'AGPL-3',
26 'author': 'Noviat',26 'author': 'Noviat',
27 'website': 'http://www.noviat.com',27 'website': 'http://www.noviat.com',
28 'category': 'Reporting',28 'category': 'Reporting',
29 'description': """ 29 'description': """
3030Excel report engine
31This module adds XLS export capabilities to the standard OpenERP reporting engine.31===================
32 32
33In 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.33This module adds Excel export capabilities to the standard OpenERP reporting engine.
34 34
35Report development
36''''''''''''''''''
37In order to create an Excel report you can\n
38- define a report of type 'xls'
39- pass ``{'xls_export': 1}`` via the context to the report create method
40
41The ``report_xls`` class contains a number of attributes and methods to facilitate
42the creation XLS reports in OpenERP.
43
44* cell types
45
46 Supported cell types : text, number, boolean, date.
47
48* cell styles
49
50 The predefined cell style definitions result in a consistent
51 look and feel of the OpenERP Excel reports.
52
53* cell formulas
54
55 Cell formulas can be easily added with the help of the ``rowcol_to_cell()`` function which
56 you can import from the ``utils.py`` module.
57
58* Excel templates
59
60 It is possible to define Excel templates which can be adapted by 'inherited' modules.
61 Download the ``account_move_line_report_xls`` module from http://apps.openerp.com
62 as example.
63
64* XLS with multiple sheets
65
66 Download the ``account_journal_report_xls`` module from http://apps.openerp.com as example.
67
68Development assistance
69''''''''''''''''''''''
70Contact info@noviat.com for help with the development of Excel reports in OpenERP, .
71
35 """,72 """,
36 'depends': ['base'],73 'depends': ['base'],
37 'external_dependencies': {'python': ['xlwt']},74 'external_dependencies': {'python': ['xlwt']},
38 'demo_xml': [],75 'demo': [],
39 'init_xml': [],76 'data': [],
40 'update_xml' : [],
41 'active': False,77 'active': False,
42 'installable': True,78 'installable': True,
43}79}
4480
=== modified file 'report_xls/report_xls.py'
--- report_xls/report_xls.py 2013-11-15 15:56:47 +0000
+++ report_xls/report_xls.py 2014-01-06 22:32:08 +0000
@@ -2,8 +2,8 @@
2##############################################################################2##############################################################################
3#3#
4# OpenERP, Open Source Management Solution4# OpenERP, Open Source Management Solution
5# 5#
6#Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved.6# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved.
7#7#
8# This program is free software: you can redistribute it and/or modify8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as9# it under the terms of the GNU Affero General Public License as
@@ -12,7 +12,7 @@
12#12#
13# This program is distributed in the hope that it will be useful,13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.16# GNU Affero General Public License for more details.
17#17#
18# You should have received a copy of the GNU Affero General Public License18# You should have received a copy of the GNU Affero General Public License
@@ -23,7 +23,8 @@
23import xlwt23import xlwt
24from xlwt.Style import default_style24from xlwt.Style import default_style
25import cStringIO25import cStringIO
26import datetime, time26from datetime import datetime
27from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
27import inspect28import inspect
28from types import CodeType29from types import CodeType
29from openerp.report.report_sxw import *30from openerp.report.report_sxw import *
@@ -32,13 +33,15 @@
32import logging33import logging
33_logger = logging.getLogger(__name__)34_logger = logging.getLogger(__name__)
3435
36
35class AttrDict(dict):37class AttrDict(dict):
36 def __init__(self, *args, **kwargs):38 def __init__(self, *args, **kwargs):
37 super(AttrDict, self).__init__(*args, **kwargs)39 super(AttrDict, self).__init__(*args, **kwargs)
38 self.__dict__ = self40 self.__dict__ = self
3941
42
40class report_xls(report_sxw):43class report_xls(report_sxw):
41 44
42 xls_types = {45 xls_types = {
43 'bool': xlwt.Row.set_cell_boolean,46 'bool': xlwt.Row.set_cell_boolean,
44 'date': xlwt.Row.set_cell_date,47 'date': xlwt.Row.set_cell_date,
@@ -53,36 +56,29 @@
53 }56 }
5457
55 # TO DO: move parameters infra to configurable data58 # TO DO: move parameters infra to configurable data
56 59
57 # header/footer60 # header/footer
58 DT_FORMAT = '%Y-%m-%d %H:%M:%S' 61 DT_FORMAT = '%Y-%m-%d %H:%M:%S'
59 hf_params = {62 hf_params = {
60 'font_size': 8,63 'font_size': 8,
61 'font_style': 'I', # B: Bold, I: Italic, U: Underline64 'font_style': 'I', # B: Bold, I: Italic, U: Underline
62 }65 }
63 xls_headers = {66
64 'standard': ''
65 }
66 xls_footers = {
67 'standard': ('&L&%(font_size)s&%(font_style)s' + datetime.now().strftime(DT_FORMAT) +
68 '&R&%(font_size)s&%(font_style)s&P / &N') %hf_params
69 }
70
71 # styles67 # styles
72 _pfc = '26' # default pattern fore_color68 _pfc = '26' # default pattern fore_color
73 _bc = '22' # borders color69 _bc = '22' # borders color
74 decimal_format = '#,##0.00'70 decimal_format = '#,##0.00'
75 date_format = 'YYYY-MM-DD' 71 date_format = 'YYYY-MM-DD'
76 xls_styles = {72 xls_styles = {
77 'xls_title': 'font: bold true, height 240;',73 'xls_title': 'font: bold true, height 240;',
78 'bold': 'font: bold true;',74 'bold': 'font: bold true;',
79 'underline': 'font: underline true;',75 'underline': 'font: underline true;',
80 'italic': 'font: italic true;',76 'italic': 'font: italic true;',
81 'fill': 'pattern: pattern solid, fore_color %s;' %_pfc,77 'fill': 'pattern: pattern solid, fore_color %s;' % _pfc,
82 'fill_blue' : 'pattern: pattern solid, fore_color 27;',78 'fill_blue': 'pattern: pattern solid, fore_color 27;',
83 'fill_grey' : 'pattern: pattern solid, fore_color 22;', 79 'fill_grey': 'pattern: pattern solid, fore_color 22;',
84 'borders_all': 'borders: left thin, right thin, top thin, bottom thin, ' \80 'borders_all': 'borders: left thin, right thin, top thin, bottom thin, '
85 'left_colour %s, right_colour %s, top_colour %s, bottom_colour %s;' %(_bc,_bc,_bc,_bc),81 'left_colour %s, right_colour %s, top_colour %s, bottom_colour %s;' % (_bc, _bc, _bc, _bc),
86 'left': 'align: horz left;',82 'left': 'align: horz left;',
87 'center': 'align: horz center;',83 'center': 'align: horz center;',
88 'right': 'align: horz right;',84 'right': 'align: horz right;',
@@ -91,8 +87,8 @@
91 'bottom': 'align: vert bottom;',87 'bottom': 'align: vert bottom;',
92 }88 }
93 # TO DO: move parameters supra to configurable data89 # TO DO: move parameters supra to configurable data
94 90
95 def create(self, cr, uid, ids, data, context=None): 91 def create(self, cr, uid, ids, data, context=None):
96 self.pool = pooler.get_pool(cr.dbname)92 self.pool = pooler.get_pool(cr.dbname)
97 self.cr = cr93 self.cr = cr
98 self.uid = uid94 self.uid = uid
@@ -105,11 +101,13 @@
105 if report_xml.report_type == 'xls':101 if report_xml.report_type == 'xls':
106 return self.create_source_xls(cr, uid, ids, data, context)102 return self.create_source_xls(cr, uid, ids, data, context)
107 elif context.get('xls_export'):103 elif context.get('xls_export'):
104 self.table = data.get('model') or self.table # use model from 'data' when no ir.actions.report.xml entry
108 return self.create_source_xls(cr, uid, ids, data, context)105 return self.create_source_xls(cr, uid, ids, data, context)
109 return super(report_xls, self).create(cr, uid, ids, data, context)106 return super(report_xls, self).create(cr, uid, ids, data, context)
110107
111 def create_source_xls(self, cr, uid, ids, data, context=None):108 def create_source_xls(self, cr, uid, ids, data, context=None):
112 if not context: context = {}109 if not context:
110 context = {}
113 parser_instance = self.parser(cr, uid, self.name2, context)111 parser_instance = self.parser(cr, uid, self.name2, context)
114 self.parser_instance = parser_instance112 self.parser_instance = parser_instance
115 objs = self.getObjects(cr, uid, ids, context)113 objs = self.getObjects(cr, uid, ids, context)
@@ -119,15 +117,22 @@
119 wb = xlwt.Workbook(encoding='utf-8')117 wb = xlwt.Workbook(encoding='utf-8')
120 _p = AttrDict(parser_instance.localcontext)118 _p = AttrDict(parser_instance.localcontext)
121 _xs = self.xls_styles119 _xs = self.xls_styles
120 self.xls_headers = {
121 'standard': '',
122 }
123 self.xls_footers = {
124 'standard': ('&L&%(font_size)s&%(font_style)s' + datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT) +
125 '&R&%(font_size)s&%(font_style)s&P / &N') % self.hf_params,
126 }
122 self.generate_xls_report(_p, _xs, data, objs, wb)127 self.generate_xls_report(_p, _xs, data, objs, wb)
123 wb.save(n)128 wb.save(n)
124 n.seek(0)129 n.seek(0)
125 return (n.read(), 'xls') 130 return (n.read(), 'xls')
126 131
127 def render(self, wanted, col_specs, rowtype, render_space='empty'):132 def render(self, wanted, col_specs, rowtype, render_space='empty'):
128 """133 """
129 returns 'mako'-rendered col_specs134 returns 'evaluated' col_specs
130 135
131 Input:136 Input:
132 - wanted: element from the wanted_list137 - wanted: element from the wanted_list
133 - col_specs : cf. specs[1:] documented in xls_row_template method138 - col_specs : cf. specs[1:] documented in xls_row_template method
@@ -139,7 +144,7 @@
139 caller_space = inspect.currentframe().f_back.f_back.f_locals144 caller_space = inspect.currentframe().f_back.f_back.f_locals
140 localcontext = self.parser_instance.localcontext145 localcontext = self.parser_instance.localcontext
141 render_space.update(caller_space)146 render_space.update(caller_space)
142 render_space.update(localcontext) 147 render_space.update(localcontext)
143 row = col_specs[wanted][rowtype][:]148 row = col_specs[wanted][rowtype][:]
144 for i in range(len(row)):149 for i in range(len(row)):
145 if isinstance(row[i], CodeType):150 if isinstance(row[i], CodeType):
@@ -155,9 +160,9 @@
155 def xls_row_template(self, specs, wanted_list):160 def xls_row_template(self, specs, wanted_list):
156 """161 """
157 Returns a row template.162 Returns a row template.
158 163
159 Input :164 Input :
160 - 'wanted_list': list of Columns that will be returned in the row_template 165 - 'wanted_list': list of Columns that will be returned in the row_template
161 - 'specs': list with Column Characteristics166 - 'specs': list with Column Characteristics
162 0: Column Name (from wanted_list)167 0: Column Name (from wanted_list)
163 1: Column Colspan168 1: Column Colspan
@@ -190,14 +195,14 @@
190 if s_len > 7 and s[7] is not None:195 if s_len > 7 and s[7] is not None:
191 c.append(s[7])196 c.append(s[7])
192 else:197 else:
193 c.append(None) 198 c.append(None)
194 r.append((col, c[1], c))199 r.append((col, c[1], c))
195 col += c[1]200 col += c[1]
196 break201 break
197 if not found:202 if not found:
198 _logger.warn("report_xls.xls_row_template, column '%s' not found in specs", w)203 _logger.warn("report_xls.xls_row_template, column '%s' not found in specs", w)
199 return r204 return r
200 205
201 def xls_write_row(self, ws, row_pos, row_data, row_style=default_style, set_column_size=False):206 def xls_write_row(self, ws, row_pos, row_data, row_style=default_style, set_column_size=False):
202 r = ws.row(row_pos)207 r = ws.row(row_pos)
203 for col, size, spec in row_data:208 for col, size, spec in row_data:
@@ -209,9 +214,9 @@
209 data = report_xls.xls_types_default[spec[3]]214 data = report_xls.xls_types_default[spec[3]]
210 if size != 1:215 if size != 1:
211 if formula:216 if formula:
212 ws.write_merge(row_pos, row_pos, col, col+size-1, data, style)217 ws.write_merge(row_pos, row_pos, col, col + size - 1, data, style)
213 else:218 else:
214 ws.write_merge(row_pos, row_pos, col, col+size-1, data, style)219 ws.write_merge(row_pos, row_pos, col, col + size - 1, data, style)
215 else:220 else:
216 if formula:221 if formula:
217 ws.write(row_pos, col, formula, style)222 ws.write(row_pos, col, formula, style)
@@ -220,5 +225,5 @@
220 if set_column_size:225 if set_column_size:
221 ws.col(col).width = spec[2] * 256226 ws.col(col).width = spec[2] * 256
222 return row_pos + 1227 return row_pos + 1
223 228
224# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:229# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
225230
=== added directory 'report_xls/static'
=== added directory 'report_xls/static/src'
=== added directory 'report_xls/static/src/img'
=== added file 'report_xls/static/src/img/icon.png'
226Binary files report_xls/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and report_xls/static/src/img/icon.png 2014-01-06 22:32:08 +0000 differ231Binary files report_xls/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and report_xls/static/src/img/icon.png 2014-01-06 22:32:08 +0000 differ
=== modified file 'report_xls/utils.py'
--- report_xls/utils.py 2013-11-15 15:56:47 +0000
+++ report_xls/utils.py 2014-01-06 22:32:08 +0000
@@ -12,17 +12,18 @@
12#12#
13# This program is distributed in the hope that it will be useful,13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.16# GNU Affero General Public License for more details.
17#17#
18# You should have received a copy of the GNU Affero General Public License18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#20#
21##############################################################################21##############################################################################
22#22
2323
24def _render(code):24def _render(code):
25 return compile(code, '<string>', 'eval') 25 return compile(code, '<string>', 'eval')
26
2627
27def rowcol_to_cell(row, col, row_abs=False, col_abs=False):28def rowcol_to_cell(row, col, row_abs=False, col_abs=False):
28 # Code based upon utils from xlwt distribution29 # Code based upon utils from xlwt distribution
@@ -41,9 +42,9 @@
41 else:42 else:
42 col_abs = ''43 col_abs = ''
43 if d > 0:44 if d > 0:
44 chr1 = chr(ord('A') + d - 1)45 chr1 = chr(ord('A') + d - 1)
45 chr2 = chr(ord('A') + m)46 chr2 = chr(ord('A') + m)
46 # Zero index to 1-index47 # Zero index to 1-index
47 return col_abs + chr1 + chr2 + row_abs + str(row + 1)48 return col_abs + chr1 + chr2 + row_abs + str(row + 1)
48 49
49# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:50# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

Subscribers

People subscribed via source and target branches