|
@ -2,8 +2,8 @@ |
|
|
############################################################################## |
|
|
############################################################################## |
|
|
# |
|
|
# |
|
|
# OpenERP, Open Source Management Solution |
|
|
# 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 |
|
|
# This program is free software: you can redistribute it and/or modify |
|
|
# it under the terms of the GNU Affero General Public License as |
|
|
# 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, |
|
|
# This program is distributed in the hope that it will be useful, |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
# 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. |
|
|
# GNU Affero General Public License for more details. |
|
|
# |
|
|
# |
|
|
# You should have received a copy of the GNU Affero General Public License |
|
|
# You should have received a copy of the GNU Affero General Public License |
|
@ -23,7 +23,8 @@ |
|
|
import xlwt |
|
|
import xlwt |
|
|
from xlwt.Style import default_style |
|
|
from xlwt.Style import default_style |
|
|
import cStringIO |
|
|
import cStringIO |
|
|
import datetime, time |
|
|
|
|
|
|
|
|
from datetime import datetime |
|
|
|
|
|
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT |
|
|
import inspect |
|
|
import inspect |
|
|
from types import CodeType |
|
|
from types import CodeType |
|
|
from openerp.report.report_sxw import * |
|
|
from openerp.report.report_sxw import * |
|
@ -32,13 +33,15 @@ from openerp.tools.translate import translate, _ |
|
|
import logging |
|
|
import logging |
|
|
_logger = logging.getLogger(__name__) |
|
|
_logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttrDict(dict): |
|
|
class AttrDict(dict): |
|
|
def __init__(self, *args, **kwargs): |
|
|
def __init__(self, *args, **kwargs): |
|
|
super(AttrDict, self).__init__(*args, **kwargs) |
|
|
super(AttrDict, self).__init__(*args, **kwargs) |
|
|
self.__dict__ = self |
|
|
self.__dict__ = self |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class report_xls(report_sxw): |
|
|
class report_xls(report_sxw): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xls_types = { |
|
|
xls_types = { |
|
|
'bool': xlwt.Row.set_cell_boolean, |
|
|
'bool': xlwt.Row.set_cell_boolean, |
|
|
'date': xlwt.Row.set_cell_date, |
|
|
'date': xlwt.Row.set_cell_date, |
|
@ -53,36 +56,29 @@ class report_xls(report_sxw): |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
# TO DO: move parameters infra to configurable data |
|
|
# TO DO: move parameters infra to configurable data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# header/footer |
|
|
# header/footer |
|
|
DT_FORMAT = '%Y-%m-%d %H:%M:%S' |
|
|
|
|
|
|
|
|
DT_FORMAT = '%Y-%m-%d %H:%M:%S' |
|
|
hf_params = { |
|
|
hf_params = { |
|
|
'font_size': 8, |
|
|
'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 |
|
|
# 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' |
|
|
decimal_format = '#,##0.00' |
|
|
date_format = 'YYYY-MM-DD' |
|
|
|
|
|
|
|
|
date_format = 'YYYY-MM-DD' |
|
|
xls_styles = { |
|
|
xls_styles = { |
|
|
'xls_title': 'font: bold true, height 240;', |
|
|
'xls_title': 'font: bold true, height 240;', |
|
|
'bold': 'font: bold true;', |
|
|
'bold': 'font: bold true;', |
|
|
'underline': 'font: underline true;', |
|
|
'underline': 'font: underline true;', |
|
|
'italic': 'font: italic 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;', |
|
|
'left': 'align: horz left;', |
|
|
'center': 'align: horz center;', |
|
|
'center': 'align: horz center;', |
|
|
'right': 'align: horz right;', |
|
|
'right': 'align: horz right;', |
|
@ -91,8 +87,8 @@ class report_xls(report_sxw): |
|
|
'bottom': 'align: vert bottom;', |
|
|
'bottom': 'align: vert bottom;', |
|
|
} |
|
|
} |
|
|
# TO DO: move parameters supra to configurable data |
|
|
# 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.pool = pooler.get_pool(cr.dbname) |
|
|
self.cr = cr |
|
|
self.cr = cr |
|
|
self.uid = uid |
|
|
self.uid = uid |
|
@ -105,11 +101,13 @@ class report_xls(report_sxw): |
|
|
if report_xml.report_type == 'xls': |
|
|
if report_xml.report_type == 'xls': |
|
|
return self.create_source_xls(cr, uid, ids, data, context) |
|
|
return self.create_source_xls(cr, uid, ids, data, context) |
|
|
elif context.get('xls_export'): |
|
|
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 self.create_source_xls(cr, uid, ids, data, context) |
|
|
return super(report_xls, self).create(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): |
|
|
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) |
|
|
parser_instance = self.parser(cr, uid, self.name2, context) |
|
|
self.parser_instance = parser_instance |
|
|
self.parser_instance = parser_instance |
|
|
objs = self.getObjects(cr, uid, ids, context) |
|
|
objs = self.getObjects(cr, uid, ids, context) |
|
@ -119,15 +117,22 @@ class report_xls(report_sxw): |
|
|
wb = xlwt.Workbook(encoding='utf-8') |
|
|
wb = xlwt.Workbook(encoding='utf-8') |
|
|
_p = AttrDict(parser_instance.localcontext) |
|
|
_p = AttrDict(parser_instance.localcontext) |
|
|
_xs = self.xls_styles |
|
|
_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) |
|
|
self.generate_xls_report(_p, _xs, data, objs, wb) |
|
|
wb.save(n) |
|
|
wb.save(n) |
|
|
n.seek(0) |
|
|
n.seek(0) |
|
|
return (n.read(), 'xls') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (n.read(), 'xls') |
|
|
|
|
|
|
|
|
def render(self, wanted, col_specs, rowtype, render_space='empty'): |
|
|
def render(self, wanted, col_specs, rowtype, render_space='empty'): |
|
|
""" |
|
|
""" |
|
|
returns 'mako'-rendered col_specs |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
returns 'evaluated' col_specs |
|
|
|
|
|
|
|
|
Input: |
|
|
Input: |
|
|
- wanted: element from the wanted_list |
|
|
- wanted: element from the wanted_list |
|
|
- col_specs : cf. specs[1:] documented in xls_row_template method |
|
|
- 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 |
|
|
caller_space = inspect.currentframe().f_back.f_back.f_locals |
|
|
localcontext = self.parser_instance.localcontext |
|
|
localcontext = self.parser_instance.localcontext |
|
|
render_space.update(caller_space) |
|
|
render_space.update(caller_space) |
|
|
render_space.update(localcontext) |
|
|
|
|
|
|
|
|
render_space.update(localcontext) |
|
|
row = col_specs[wanted][rowtype][:] |
|
|
row = col_specs[wanted][rowtype][:] |
|
|
for i in range(len(row)): |
|
|
for i in range(len(row)): |
|
|
if isinstance(row[i], CodeType): |
|
|
if isinstance(row[i], CodeType): |
|
@ -155,9 +160,9 @@ class report_xls(report_sxw): |
|
|
def xls_row_template(self, specs, wanted_list): |
|
|
def xls_row_template(self, specs, wanted_list): |
|
|
""" |
|
|
""" |
|
|
Returns a row template. |
|
|
Returns a row template. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Input : |
|
|
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 |
|
|
- 'specs': list with Column Characteristics |
|
|
0: Column Name (from wanted_list) |
|
|
0: Column Name (from wanted_list) |
|
|
1: Column Colspan |
|
|
1: Column Colspan |
|
@ -190,14 +195,14 @@ class report_xls(report_sxw): |
|
|
if s_len > 7 and s[7] is not None: |
|
|
if s_len > 7 and s[7] is not None: |
|
|
c.append(s[7]) |
|
|
c.append(s[7]) |
|
|
else: |
|
|
else: |
|
|
c.append(None) |
|
|
|
|
|
|
|
|
c.append(None) |
|
|
r.append((col, c[1], c)) |
|
|
r.append((col, c[1], c)) |
|
|
col += c[1] |
|
|
col += c[1] |
|
|
break |
|
|
break |
|
|
if not found: |
|
|
if not found: |
|
|
_logger.warn("report_xls.xls_row_template, column '%s' not found in specs", w) |
|
|
_logger.warn("report_xls.xls_row_template, column '%s' not found in specs", w) |
|
|
return r |
|
|
return r |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def xls_write_row(self, ws, row_pos, row_data, row_style=default_style, set_column_size=False): |
|
|
def xls_write_row(self, ws, row_pos, row_data, row_style=default_style, set_column_size=False): |
|
|
r = ws.row(row_pos) |
|
|
r = ws.row(row_pos) |
|
|
for col, size, spec in row_data: |
|
|
for col, size, spec in row_data: |
|
@ -209,9 +214,9 @@ class report_xls(report_sxw): |
|
|
data = report_xls.xls_types_default[spec[3]] |
|
|
data = report_xls.xls_types_default[spec[3]] |
|
|
if size != 1: |
|
|
if size != 1: |
|
|
if formula: |
|
|
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: |
|
|
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: |
|
|
else: |
|
|
if formula: |
|
|
if formula: |
|
|
ws.write(row_pos, col, formula, style) |
|
|
ws.write(row_pos, col, formula, style) |
|
@ -220,5 +225,5 @@ class report_xls(report_sxw): |
|
|
if set_column_size: |
|
|
if set_column_size: |
|
|
ws.col(col).width = spec[2] * 256 |
|
|
ws.col(col).width = spec[2] * 256 |
|
|
return row_pos + 1 |
|
|
return row_pos + 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
|
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |