Merge lp:~luc-demeyer/openerp-reporting-engines/datetime-fix-report_xls into lp:openerp-reporting-engines
- datetime-fix-report_xls
- Merge into 7.0
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 |
Related bugs: |
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 |
Commit message
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 : | # |
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
1 | === modified file 'report_xls/__init__.py' |
2 | --- report_xls/__init__.py 2013-11-15 15:56:47 +0000 |
3 | +++ report_xls/__init__.py 2014-01-06 22:32:08 +0000 |
4 | @@ -12,7 +12,7 @@ |
5 | # |
6 | # This program is distributed in the hope that it will be useful, |
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
8 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
9 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | # GNU Affero General Public License for more details. |
11 | # |
12 | # You should have received a copy of the GNU Affero General Public License |
13 | |
14 | === modified file 'report_xls/__openerp__.py' |
15 | --- report_xls/__openerp__.py 2013-11-15 15:56:47 +0000 |
16 | +++ report_xls/__openerp__.py 2014-01-06 22:32:08 +0000 |
17 | @@ -12,7 +12,7 @@ |
18 | # |
19 | # This program is distributed in the hope that it will be useful, |
20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | # GNU Affero General Public License for more details. |
24 | # |
25 | # You should have received a copy of the GNU Affero General Public License |
26 | @@ -20,24 +20,60 @@ |
27 | # |
28 | ############################################################################## |
29 | { |
30 | - 'name': 'XLS report engine', |
31 | - 'version': '0.3', |
32 | + 'name': 'Excel report engine', |
33 | + 'version': '0.4', |
34 | 'license': 'AGPL-3', |
35 | 'author': 'Noviat', |
36 | 'website': 'http://www.noviat.com', |
37 | 'category': 'Reporting', |
38 | - 'description': """ |
39 | - |
40 | -This module adds XLS export capabilities to the standard OpenERP reporting engine. |
41 | - |
42 | -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. |
43 | - |
44 | + 'description': """ |
45 | +Excel report engine |
46 | +=================== |
47 | + |
48 | +This module adds Excel export capabilities to the standard OpenERP reporting engine. |
49 | + |
50 | +Report development |
51 | +'''''''''''''''''' |
52 | +In order to create an Excel report you can\n |
53 | +- define a report of type 'xls' |
54 | +- pass ``{'xls_export': 1}`` via the context to the report create method |
55 | + |
56 | +The ``report_xls`` class contains a number of attributes and methods to facilitate |
57 | +the creation XLS reports in OpenERP. |
58 | + |
59 | +* cell types |
60 | + |
61 | + Supported cell types : text, number, boolean, date. |
62 | + |
63 | +* cell styles |
64 | + |
65 | + The predefined cell style definitions result in a consistent |
66 | + look and feel of the OpenERP Excel reports. |
67 | + |
68 | +* cell formulas |
69 | + |
70 | + Cell formulas can be easily added with the help of the ``rowcol_to_cell()`` function which |
71 | + you can import from the ``utils.py`` module. |
72 | + |
73 | +* Excel templates |
74 | + |
75 | + It is possible to define Excel templates which can be adapted by 'inherited' modules. |
76 | + Download the ``account_move_line_report_xls`` module from http://apps.openerp.com |
77 | + as example. |
78 | + |
79 | +* XLS with multiple sheets |
80 | + |
81 | + Download the ``account_journal_report_xls`` module from http://apps.openerp.com as example. |
82 | + |
83 | +Development assistance |
84 | +'''''''''''''''''''''' |
85 | +Contact info@noviat.com for help with the development of Excel reports in OpenERP, . |
86 | + |
87 | """, |
88 | 'depends': ['base'], |
89 | 'external_dependencies': {'python': ['xlwt']}, |
90 | - 'demo_xml': [], |
91 | - 'init_xml': [], |
92 | - 'update_xml' : [], |
93 | + 'demo': [], |
94 | + 'data': [], |
95 | 'active': False, |
96 | 'installable': True, |
97 | } |
98 | |
99 | === modified file 'report_xls/report_xls.py' |
100 | --- report_xls/report_xls.py 2013-11-15 15:56:47 +0000 |
101 | +++ report_xls/report_xls.py 2014-01-06 22:32:08 +0000 |
102 | @@ -2,8 +2,8 @@ |
103 | ############################################################################## |
104 | # |
105 | # OpenERP, Open Source Management Solution |
106 | -# |
107 | -#Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. |
108 | +# |
109 | +# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. |
110 | # |
111 | # This program is free software: you can redistribute it and/or modify |
112 | # it under the terms of the GNU Affero General Public License as |
113 | @@ -12,7 +12,7 @@ |
114 | # |
115 | # This program is distributed in the hope that it will be useful, |
116 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
117 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
118 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
119 | # GNU Affero General Public License for more details. |
120 | # |
121 | # You should have received a copy of the GNU Affero General Public License |
122 | @@ -23,7 +23,8 @@ |
123 | import xlwt |
124 | from xlwt.Style import default_style |
125 | import cStringIO |
126 | -import datetime, time |
127 | +from datetime import datetime |
128 | +from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT |
129 | import inspect |
130 | from types import CodeType |
131 | from openerp.report.report_sxw import * |
132 | @@ -32,13 +33,15 @@ |
133 | import logging |
134 | _logger = logging.getLogger(__name__) |
135 | |
136 | + |
137 | class AttrDict(dict): |
138 | def __init__(self, *args, **kwargs): |
139 | super(AttrDict, self).__init__(*args, **kwargs) |
140 | self.__dict__ = self |
141 | |
142 | + |
143 | class report_xls(report_sxw): |
144 | - |
145 | + |
146 | xls_types = { |
147 | 'bool': xlwt.Row.set_cell_boolean, |
148 | 'date': xlwt.Row.set_cell_date, |
149 | @@ -53,36 +56,29 @@ |
150 | } |
151 | |
152 | # TO DO: move parameters infra to configurable data |
153 | - |
154 | + |
155 | # header/footer |
156 | - DT_FORMAT = '%Y-%m-%d %H:%M:%S' |
157 | + DT_FORMAT = '%Y-%m-%d %H:%M:%S' |
158 | hf_params = { |
159 | 'font_size': 8, |
160 | - 'font_style': 'I', # B: Bold, I: Italic, U: Underline |
161 | - } |
162 | - xls_headers = { |
163 | - 'standard': '' |
164 | - } |
165 | - xls_footers = { |
166 | - 'standard': ('&L&%(font_size)s&%(font_style)s' + datetime.now().strftime(DT_FORMAT) + |
167 | - '&R&%(font_size)s&%(font_style)s&P / &N') %hf_params |
168 | - } |
169 | - |
170 | + 'font_style': 'I', # B: Bold, I: Italic, U: Underline |
171 | + } |
172 | + |
173 | # styles |
174 | - _pfc = '26' # default pattern fore_color |
175 | - _bc = '22' # borders color |
176 | + _pfc = '26' # default pattern fore_color |
177 | + _bc = '22' # borders color |
178 | decimal_format = '#,##0.00' |
179 | - date_format = 'YYYY-MM-DD' |
180 | + date_format = 'YYYY-MM-DD' |
181 | xls_styles = { |
182 | 'xls_title': 'font: bold true, height 240;', |
183 | 'bold': 'font: bold true;', |
184 | 'underline': 'font: underline true;', |
185 | 'italic': 'font: italic true;', |
186 | - 'fill': 'pattern: pattern solid, fore_color %s;' %_pfc, |
187 | - 'fill_blue' : 'pattern: pattern solid, fore_color 27;', |
188 | - 'fill_grey' : 'pattern: pattern solid, fore_color 22;', |
189 | - 'borders_all': 'borders: left thin, right thin, top thin, bottom thin, ' \ |
190 | - 'left_colour %s, right_colour %s, top_colour %s, bottom_colour %s;' %(_bc,_bc,_bc,_bc), |
191 | + 'fill': 'pattern: pattern solid, fore_color %s;' % _pfc, |
192 | + 'fill_blue': 'pattern: pattern solid, fore_color 27;', |
193 | + 'fill_grey': 'pattern: pattern solid, fore_color 22;', |
194 | + 'borders_all': 'borders: left thin, right thin, top thin, bottom thin, ' |
195 | + 'left_colour %s, right_colour %s, top_colour %s, bottom_colour %s;' % (_bc, _bc, _bc, _bc), |
196 | 'left': 'align: horz left;', |
197 | 'center': 'align: horz center;', |
198 | 'right': 'align: horz right;', |
199 | @@ -91,8 +87,8 @@ |
200 | 'bottom': 'align: vert bottom;', |
201 | } |
202 | # TO DO: move parameters supra to configurable data |
203 | - |
204 | - def create(self, cr, uid, ids, data, context=None): |
205 | + |
206 | + def create(self, cr, uid, ids, data, context=None): |
207 | self.pool = pooler.get_pool(cr.dbname) |
208 | self.cr = cr |
209 | self.uid = uid |
210 | @@ -105,11 +101,13 @@ |
211 | if report_xml.report_type == 'xls': |
212 | return self.create_source_xls(cr, uid, ids, data, context) |
213 | elif context.get('xls_export'): |
214 | + self.table = data.get('model') or self.table # use model from 'data' when no ir.actions.report.xml entry |
215 | return self.create_source_xls(cr, uid, ids, data, context) |
216 | return super(report_xls, self).create(cr, uid, ids, data, context) |
217 | |
218 | def create_source_xls(self, cr, uid, ids, data, context=None): |
219 | - if not context: context = {} |
220 | + if not context: |
221 | + context = {} |
222 | parser_instance = self.parser(cr, uid, self.name2, context) |
223 | self.parser_instance = parser_instance |
224 | objs = self.getObjects(cr, uid, ids, context) |
225 | @@ -119,15 +117,22 @@ |
226 | wb = xlwt.Workbook(encoding='utf-8') |
227 | _p = AttrDict(parser_instance.localcontext) |
228 | _xs = self.xls_styles |
229 | + self.xls_headers = { |
230 | + 'standard': '', |
231 | + } |
232 | + self.xls_footers = { |
233 | + 'standard': ('&L&%(font_size)s&%(font_style)s' + datetime.now().strftime(DEFAULT_SERVER_DATETIME_FORMAT) + |
234 | + '&R&%(font_size)s&%(font_style)s&P / &N') % self.hf_params, |
235 | + } |
236 | self.generate_xls_report(_p, _xs, data, objs, wb) |
237 | wb.save(n) |
238 | n.seek(0) |
239 | - return (n.read(), 'xls') |
240 | - |
241 | + return (n.read(), 'xls') |
242 | + |
243 | def render(self, wanted, col_specs, rowtype, render_space='empty'): |
244 | """ |
245 | - returns 'mako'-rendered col_specs |
246 | - |
247 | + returns 'evaluated' col_specs |
248 | + |
249 | Input: |
250 | - wanted: element from the wanted_list |
251 | - col_specs : cf. specs[1:] documented in xls_row_template method |
252 | @@ -139,7 +144,7 @@ |
253 | caller_space = inspect.currentframe().f_back.f_back.f_locals |
254 | localcontext = self.parser_instance.localcontext |
255 | render_space.update(caller_space) |
256 | - render_space.update(localcontext) |
257 | + render_space.update(localcontext) |
258 | row = col_specs[wanted][rowtype][:] |
259 | for i in range(len(row)): |
260 | if isinstance(row[i], CodeType): |
261 | @@ -155,9 +160,9 @@ |
262 | def xls_row_template(self, specs, wanted_list): |
263 | """ |
264 | Returns a row template. |
265 | - |
266 | + |
267 | Input : |
268 | - - 'wanted_list': list of Columns that will be returned in the row_template |
269 | + - 'wanted_list': list of Columns that will be returned in the row_template |
270 | - 'specs': list with Column Characteristics |
271 | 0: Column Name (from wanted_list) |
272 | 1: Column Colspan |
273 | @@ -190,14 +195,14 @@ |
274 | if s_len > 7 and s[7] is not None: |
275 | c.append(s[7]) |
276 | else: |
277 | - c.append(None) |
278 | + c.append(None) |
279 | r.append((col, c[1], c)) |
280 | col += c[1] |
281 | break |
282 | if not found: |
283 | _logger.warn("report_xls.xls_row_template, column '%s' not found in specs", w) |
284 | return r |
285 | - |
286 | + |
287 | def xls_write_row(self, ws, row_pos, row_data, row_style=default_style, set_column_size=False): |
288 | r = ws.row(row_pos) |
289 | for col, size, spec in row_data: |
290 | @@ -209,9 +214,9 @@ |
291 | data = report_xls.xls_types_default[spec[3]] |
292 | if size != 1: |
293 | if formula: |
294 | - ws.write_merge(row_pos, row_pos, col, col+size-1, data, style) |
295 | + ws.write_merge(row_pos, row_pos, col, col + size - 1, data, style) |
296 | else: |
297 | - ws.write_merge(row_pos, row_pos, col, col+size-1, data, style) |
298 | + ws.write_merge(row_pos, row_pos, col, col + size - 1, data, style) |
299 | else: |
300 | if formula: |
301 | ws.write(row_pos, col, formula, style) |
302 | @@ -220,5 +225,5 @@ |
303 | if set_column_size: |
304 | ws.col(col).width = spec[2] * 256 |
305 | return row_pos + 1 |
306 | - |
307 | + |
308 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
309 | |
310 | === added directory 'report_xls/static' |
311 | === added directory 'report_xls/static/src' |
312 | === added directory 'report_xls/static/src/img' |
313 | === added file 'report_xls/static/src/img/icon.png' |
314 | Binary 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 |
315 | === modified file 'report_xls/utils.py' |
316 | --- report_xls/utils.py 2013-11-15 15:56:47 +0000 |
317 | +++ report_xls/utils.py 2014-01-06 22:32:08 +0000 |
318 | @@ -12,17 +12,18 @@ |
319 | # |
320 | # This program is distributed in the hope that it will be useful, |
321 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
322 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
323 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
324 | # GNU Affero General Public License for more details. |
325 | # |
326 | # You should have received a copy of the GNU Affero General Public License |
327 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
328 | # |
329 | ############################################################################## |
330 | -# |
331 | + |
332 | |
333 | def _render(code): |
334 | - return compile(code, '<string>', 'eval') |
335 | + return compile(code, '<string>', 'eval') |
336 | + |
337 | |
338 | def rowcol_to_cell(row, col, row_abs=False, col_abs=False): |
339 | # Code based upon utils from xlwt distribution |
340 | @@ -41,9 +42,9 @@ |
341 | else: |
342 | col_abs = '' |
343 | if d > 0: |
344 | - chr1 = chr(ord('A') + d - 1) |
345 | + chr1 = chr(ord('A') + d - 1) |
346 | chr2 = chr(ord('A') + m) |
347 | # Zero index to 1-index |
348 | return col_abs + chr1 + chr2 + row_abs + str(row + 1) |
349 | - |
350 | + |
351 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
Hi,
Thanks for this cleanup, very much appreciated.
LGTM,
Regards,