mirror of
https://github.com/OCA/reporting-engine.git
synced 2025-02-16 16:30:38 +02:00
style & documentation refresh, xls footer datetime fix
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -20,24 +20,60 @@
|
|||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
{
|
{
|
||||||
'name': 'XLS report engine',
|
'name': 'Excel report engine',
|
||||||
'version': '0.3',
|
'version': '0.4',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'author': 'Noviat',
|
'author': 'Noviat',
|
||||||
'website': 'http://www.noviat.com',
|
'website': 'http://www.noviat.com',
|
||||||
'category': 'Reporting',
|
'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'],
|
'depends': ['base'],
|
||||||
'external_dependencies': {'python': ['xlwt']},
|
'external_dependencies': {'python': ['xlwt']},
|
||||||
'demo_xml': [],
|
'demo': [],
|
||||||
'init_xml': [],
|
'data': [],
|
||||||
'update_xml' : [],
|
|
||||||
'active': False,
|
'active': False,
|
||||||
'installable': True,
|
'installable': True,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
'font_style': 'I', # B: Bold, I: Italic, U: Underline
|
||||||
}
|
}
|
||||||
xls_headers = {
|
|
||||||
'standard': ''
|
|
||||||
}
|
|
||||||
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
|
_pfc = '26' # default pattern fore_color
|
||||||
_bc = '22' # borders 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': 'pattern: pattern solid, fore_color %s;' % _pfc,
|
||||||
'fill_blue' : 'pattern: pattern solid, fore_color 27;',
|
'fill_blue': 'pattern: pattern solid, fore_color 27;',
|
||||||
'fill_grey' : 'pattern: pattern solid, fore_color 22;',
|
'fill_grey': 'pattern: pattern solid, fore_color 22;',
|
||||||
'borders_all': 'borders: left thin, right thin, top thin, bottom thin, ' \
|
'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_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:
|
||||||
|
|||||||
BIN
report_xls/static/src/img/icon.png
Normal file
BIN
report_xls/static/src/img/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -12,17 +12,18 @@
|
|||||||
#
|
#
|
||||||
# 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
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
|
||||||
|
|
||||||
def _render(code):
|
def _render(code):
|
||||||
return compile(code, '<string>', 'eval')
|
return compile(code, '<string>', 'eval')
|
||||||
|
|
||||||
|
|
||||||
def rowcol_to_cell(row, col, row_abs=False, col_abs=False):
|
def rowcol_to_cell(row, col, row_abs=False, col_abs=False):
|
||||||
# Code based upon utils from xlwt distribution
|
# Code based upon utils from xlwt distribution
|
||||||
@@ -41,9 +42,9 @@ def rowcol_to_cell(row, col, row_abs=False, col_abs=False):
|
|||||||
else:
|
else:
|
||||||
col_abs = ''
|
col_abs = ''
|
||||||
if d > 0:
|
if d > 0:
|
||||||
chr1 = chr(ord('A') + d - 1)
|
chr1 = chr(ord('A') + d - 1)
|
||||||
chr2 = chr(ord('A') + m)
|
chr2 = chr(ord('A') + m)
|
||||||
# Zero index to 1-index
|
# Zero index to 1-index
|
||||||
return col_abs + chr1 + chr2 + row_abs + str(row + 1)
|
return col_abs + chr1 + chr2 + row_abs + str(row + 1)
|
||||||
|
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|||||||
Reference in New Issue
Block a user