Merge lp:~bcim/openerp-reporting-engines/7.0-report_xls into lp:openerp-reporting-engines

Proposed by Jacques-Etienne Baudoux
Status: Merged
Merged at revision: 2
Proposed branch: lp:~bcim/openerp-reporting-engines/7.0-report_xls
Merge into: lp:openerp-reporting-engines
Diff against target: 361 lines (+341/-0)
4 files modified
report_xls/__init__.py (+24/-0)
report_xls/__openerp__.py (+44/-0)
report_xls/report_xls.py (+224/-0)
report_xls/utils.py (+49/-0)
To merge this branch: bzr merge lp:~bcim/openerp-reporting-engines/7.0-report_xls
Reviewer Review Type Date Requested Status
Joël Grand-Guillaume @ camptocamp code review, no tests Approve
Jacques-Etienne Baudoux (community) test Approve
Review via email: mp+195412@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
Jacques-Etienne Baudoux (jbaudoux) wrote :

Works on saas1

review: Approve (test)
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

The beginning of the discussion of this module starts here:

https://code.launchpad.net/~luc-demeyer/server-env-tools/7.0-report_xls/+merge/192242

Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

LGTM, Thanks for this contribs

review: Approve (code review, no tests)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'report_xls'
=== added file 'report_xls/__init__.py'
--- report_xls/__init__.py 1970-01-01 00:00:00 +0000
+++ report_xls/__init__.py 2013-11-15 16:03:10 +0000
@@ -0,0 +1,24 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5#
6# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved.
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# 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/>.
20#
21##############################################################################
22
23from . import report_xls
24# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
025
=== added file 'report_xls/__openerp__.py'
--- report_xls/__openerp__.py 1970-01-01 00:00:00 +0000
+++ report_xls/__openerp__.py 2013-11-15 16:03:10 +0000
@@ -0,0 +1,44 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5#
6# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved.
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# 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/>.
20#
21##############################################################################
22{
23 'name': 'XLS report engine',
24 'version': '0.3',
25 'license': 'AGPL-3',
26 'author': 'Noviat',
27 'website': 'http://www.noviat.com',
28 'category': 'Reporting',
29 'description': """
30
31This module adds XLS export capabilities to the standard OpenERP reporting engine.
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.
34
35 """,
36 'depends': ['base'],
37 'external_dependencies': {'python': ['xlwt']},
38 'demo_xml': [],
39 'init_xml': [],
40 'update_xml' : [],
41 'active': False,
42 'installable': True,
43}
44# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
045
=== added file 'report_xls/report_xls.py'
--- report_xls/report_xls.py 1970-01-01 00:00:00 +0000
+++ report_xls/report_xls.py 2013-11-15 16:03:10 +0000
@@ -0,0 +1,224 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5#
6#Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved.
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# 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/>.
20#
21##############################################################################
22
23import xlwt
24from xlwt.Style import default_style
25import cStringIO
26import datetime, time
27import inspect
28from types import CodeType
29from openerp.report.report_sxw import *
30from openerp import pooler
31from openerp.tools.translate import translate, _
32import logging
33_logger = logging.getLogger(__name__)
34
35class AttrDict(dict):
36 def __init__(self, *args, **kwargs):
37 super(AttrDict, self).__init__(*args, **kwargs)
38 self.__dict__ = self
39
40class report_xls(report_sxw):
41
42 xls_types = {
43 'bool': xlwt.Row.set_cell_boolean,
44 'date': xlwt.Row.set_cell_date,
45 'text': xlwt.Row.set_cell_text,
46 'number': xlwt.Row.set_cell_number,
47 }
48 xls_types_default = {
49 'bool': False,
50 'date': None,
51 'text': '',
52 'number': 0,
53 }
54
55 # TO DO: move parameters infra to configurable data
56
57 # header/footer
58 DT_FORMAT = '%Y-%m-%d %H:%M:%S'
59 hf_params = {
60 'font_size': 8,
61 'font_style': 'I', # B: Bold, I: Italic, U: Underline
62 }
63 xls_headers = {
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 # styles
72 _pfc = '26' # default pattern fore_color
73 _bc = '22' # borders color
74 decimal_format = '#,##0.00'
75 date_format = 'YYYY-MM-DD'
76 xls_styles = {
77 'xls_title': 'font: bold true, height 240;',
78 'bold': 'font: bold true;',
79 'underline': 'font: underline true;',
80 'italic': 'font: italic true;',
81 'fill': 'pattern: pattern solid, fore_color %s;' %_pfc,
82 'fill_blue' : 'pattern: pattern solid, fore_color 27;',
83 'fill_grey' : 'pattern: pattern solid, fore_color 22;',
84 '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),
86 'left': 'align: horz left;',
87 'center': 'align: horz center;',
88 'right': 'align: horz right;',
89 'wrap': 'align: wrap true;',
90 'top': 'align: vert top;',
91 'bottom': 'align: vert bottom;',
92 }
93 # TO DO: move parameters supra to configurable data
94
95 def create(self, cr, uid, ids, data, context=None):
96 self.pool = pooler.get_pool(cr.dbname)
97 self.cr = cr
98 self.uid = uid
99 report_obj = self.pool.get('ir.actions.report.xml')
100 report_ids = report_obj.search(cr, uid,
101 [('report_name', '=', self.name[7:])], context=context)
102 if report_ids:
103 report_xml = report_obj.browse(cr, uid, report_ids[0], context=context)
104 self.title = report_xml.name
105 if report_xml.report_type == 'xls':
106 return self.create_source_xls(cr, uid, ids, data, context)
107 elif context.get('xls_export'):
108 return self.create_source_xls(cr, uid, ids, data, context)
109 return super(report_xls, self).create(cr, uid, ids, data, context)
110
111 def create_source_xls(self, cr, uid, ids, data, context=None):
112 if not context: context = {}
113 parser_instance = self.parser(cr, uid, self.name2, context)
114 self.parser_instance = parser_instance
115 objs = self.getObjects(cr, uid, ids, context)
116 parser_instance.set_context(objs, data, ids, 'xls')
117 objs = parser_instance.localcontext['objects']
118 n = cStringIO.StringIO()
119 wb = xlwt.Workbook(encoding='utf-8')
120 _p = AttrDict(parser_instance.localcontext)
121 _xs = self.xls_styles
122 self.generate_xls_report(_p, _xs, data, objs, wb)
123 wb.save(n)
124 n.seek(0)
125 return (n.read(), 'xls')
126
127 def render(self, wanted, col_specs, rowtype, render_space='empty'):
128 """
129 returns 'mako'-rendered col_specs
130
131 Input:
132 - wanted: element from the wanted_list
133 - col_specs : cf. specs[1:] documented in xls_row_template method
134 - rowtype : 'header' or 'data'
135 - render_space : type dict, (caller_space + localcontext) if not specified
136 """
137 if render_space == 'empty':
138 render_space = {}
139 caller_space = inspect.currentframe().f_back.f_back.f_locals
140 localcontext = self.parser_instance.localcontext
141 render_space.update(caller_space)
142 render_space.update(localcontext)
143 row = col_specs[wanted][rowtype][:]
144 for i in range(len(row)):
145 if isinstance(row[i], CodeType):
146 row[i] = eval(row[i], render_space)
147 row.insert(0, wanted)
148 #_logger.warn('row O = %s', row)
149 return row
150
151 def generate_xls_report(self, parser, xls_styles, data, objects, wb):
152 """ override this method to create your excel file """
153 raise NotImplementedError()
154
155 def xls_row_template(self, specs, wanted_list):
156 """
157 Returns a row template.
158
159 Input :
160 - 'wanted_list': list of Columns that will be returned in the row_template
161 - 'specs': list with Column Characteristics
162 0: Column Name (from wanted_list)
163 1: Column Colspan
164 2: Column Size (unit = the width of the character ’0′ as it appears in the sheet’s default font)
165 3: Column Type
166 4: Column Data
167 5: Column Formula (or 'None' for Data)
168 6: Column Style
169 """
170 r = []
171 col = 0
172 for w in wanted_list:
173 found = False
174 for s in specs:
175 if s[0] == w:
176 found = True
177 s_len = len(s)
178 c = list(s[:5])
179 # set write_cell_func or formula
180 if s_len > 5 and s[5] is not None:
181 c.append({'formula': s[5]})
182 else:
183 c.append({'write_cell_func': report_xls.xls_types[c[3]]})
184 # Set custom cell style
185 if s_len > 6 and s[6] is not None:
186 c.append(s[6])
187 else:
188 c.append(None)
189 # Set cell formula
190 if s_len > 7 and s[7] is not None:
191 c.append(s[7])
192 else:
193 c.append(None)
194 r.append((col, c[1], c))
195 col += c[1]
196 break
197 if not found:
198 _logger.warn("report_xls.xls_row_template, column '%s' not found in specs", w)
199 return r
200
201 def xls_write_row(self, ws, row_pos, row_data, row_style=default_style, set_column_size=False):
202 r = ws.row(row_pos)
203 for col, size, spec in row_data:
204 data = spec[4]
205 formula = spec[5].get('formula') and xlwt.Formula(spec[5]['formula']) or None
206 style = spec[6] and spec[6] or row_style
207 if not data:
208 # if no data, use default values
209 data = report_xls.xls_types_default[spec[3]]
210 if size != 1:
211 if formula:
212 ws.write_merge(row_pos, row_pos, col, col+size-1, data, style)
213 else:
214 ws.write_merge(row_pos, row_pos, col, col+size-1, data, style)
215 else:
216 if formula:
217 ws.write(row_pos, col, formula, style)
218 else:
219 spec[5]['write_cell_func'](r, col, data, style)
220 if set_column_size:
221 ws.col(col).width = spec[2] * 256
222 return row_pos + 1
223
224# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0225
=== added file 'report_xls/utils.py'
--- report_xls/utils.py 1970-01-01 00:00:00 +0000
+++ report_xls/utils.py 2013-11-15 16:03:10 +0000
@@ -0,0 +1,49 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5#
6# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved.
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# 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/>.
20#
21##############################################################################
22#
23
24def _render(code):
25 return compile(code, '<string>', 'eval')
26
27def rowcol_to_cell(row, col, row_abs=False, col_abs=False):
28 # Code based upon utils from xlwt distribution
29 """
30 Convert numeric row/col notation to an Excel cell reference string in A1 notation.
31 """
32 d = col // 26
33 m = col % 26
34 chr1 = "" # Most significant character in AA1
35 if row_abs:
36 row_abs = '$'
37 else:
38 row_abs = ''
39 if col_abs:
40 col_abs = '$'
41 else:
42 col_abs = ''
43 if d > 0:
44 chr1 = chr(ord('A') + d - 1)
45 chr2 = chr(ord('A') + m)
46 # Zero index to 1-index
47 return col_abs + chr1 + chr2 + row_abs + str(row + 1)
48
49# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

Subscribers

People subscribed via source and target branches