From 51999b55a289b3cb021e8327fd24a0cf76fbb4bc Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Tue, 22 Oct 2013 23:31:59 +0200 Subject: [PATCH 1/3] add account_move_line_report_xls --- account_move_line_report_xls/__init__.py | 24 ++ account_move_line_report_xls/__openerp__.py | 38 ++++ .../account_move_line.py | 36 +++ .../report/__init__.py | 23 ++ .../report/move_line_list_xls.py | 208 ++++++++++++++++++ .../report/move_line_list_xls.xml | 22 ++ 6 files changed, 351 insertions(+) create mode 100644 account_move_line_report_xls/__init__.py create mode 100644 account_move_line_report_xls/__openerp__.py create mode 100644 account_move_line_report_xls/account_move_line.py create mode 100644 account_move_line_report_xls/report/__init__.py create mode 100644 account_move_line_report_xls/report/move_line_list_xls.py create mode 100644 account_move_line_report_xls/report/move_line_list_xls.xml diff --git a/account_move_line_report_xls/__init__.py b/account_move_line_report_xls/__init__.py new file mode 100644 index 00000000..6ad98d0c --- /dev/null +++ b/account_move_line_report_xls/__init__.py @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# +# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import account_move_line +import report diff --git a/account_move_line_report_xls/__openerp__.py b/account_move_line_report_xls/__openerp__.py new file mode 100644 index 00000000..cc24b208 --- /dev/null +++ b/account_move_line_report_xls/__openerp__.py @@ -0,0 +1,38 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# +# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{ + 'name': 'Account Move Line XLS export', + 'version': '0.2', + 'license': 'AGPL-3', + 'author': 'Noviat', + 'category' : 'Accounting & Finance', + 'description': """ + This module adds a button on the journal items ('account.move.line') list view in order to export the selected lines. + """, + 'depends': ['account', 'report_xls'], + 'demo_xml': [], + 'init_xml': [], + 'update_xml' : [ + 'report/move_line_list_xls.xml', + ], +} diff --git a/account_move_line_report_xls/account_move_line.py b/account_move_line_report_xls/account_move_line.py new file mode 100644 index 00000000..2d12f38a --- /dev/null +++ b/account_move_line_report_xls/account_move_line.py @@ -0,0 +1,36 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# +# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from osv import osv, fields + +class account_move_line(osv.osv): + _inherit = 'account.move.line' + + # override list in custom module to add/drop columns or change order + def _report_xls_fields(self, cr, uid, context=None): + return [ + 'move', 'name', 'date', 'period', 'partner', 'account', + 'date_maturity', 'debit', 'credit', 'balance', 'reconcile', 'reconcile_partial', + ] + + +account_move_line() diff --git a/account_move_line_report_xls/report/__init__.py b/account_move_line_report_xls/report/__init__.py new file mode 100644 index 00000000..cb01ef04 --- /dev/null +++ b/account_move_line_report_xls/report/__init__.py @@ -0,0 +1,23 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# +# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import move_line_list_xls diff --git a/account_move_line_report_xls/report/move_line_list_xls.py b/account_move_line_report_xls/report/move_line_list_xls.py new file mode 100644 index 00000000..9bc5b06c --- /dev/null +++ b/account_move_line_report_xls/report/move_line_list_xls.py @@ -0,0 +1,208 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# +# Copyright (c) 2013 Noviat nv/sa (www.noviat.com). All rights reserved. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import xlwt +import time +from datetime import datetime +from report import report_sxw +from report_xls.report_xls import report_xls +from report_xls.utils import rowcol_to_cell, _render +from account_move_line_report.report.move_line_list_print import move_line_list_print +from tools.translate import _ +import pooler +import logging +_logger = logging.getLogger(__name__) + + +class move_line_xls_parser(report_sxw.rml_parse): + + def __init__(self, cr, uid, name, context): + super(move_line_xls_parser, self).__init__(cr, uid, name, context=context) + self.context = context + wanted_list = self.pool.get('account.move.line')._report_xls_fields(cr, uid, context) + self.localcontext.update({ + 'datetime': datetime, + 'wanted_list': wanted_list, + }) + +class move_line_xls(report_xls): + + def __init__(self, name, table, rml=False, parser=False, header=True, store=False): + super(move_line_xls, self).__init__(name, table, rml, parser, header, store) + + # Cell Styles + _xs = self.xls_styles + # header + rh_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all'] + self.rh_cell_style = xlwt.easyxf(rh_cell_format) + self.rh_cell_style_center = xlwt.easyxf(rh_cell_format + _xs['center']) + self.rh_cell_style_right = xlwt.easyxf(rh_cell_format + _xs['right']) + # lines + aml_cell_format = _xs['borders_all'] + self.aml_cell_style = xlwt.easyxf(aml_cell_format) + self.aml_cell_style_center = xlwt.easyxf(aml_cell_format + _xs['center']) + self.aml_cell_style_date = xlwt.easyxf(aml_cell_format + _xs['left'], num_format_str = report_xls.date_format) + self.aml_cell_style_decimal = xlwt.easyxf(aml_cell_format + _xs['right'], num_format_str = report_xls.decimal_format) + # totals + rt_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all'] + self.rt_cell_style = xlwt.easyxf(rt_cell_format) + self.rt_cell_style_right = xlwt.easyxf(rt_cell_format + _xs['right']) + self.rt_cell_style_decimal = xlwt.easyxf(rt_cell_format + _xs['right'], num_format_str = report_xls.decimal_format) + + # XLS Template + self.col_specs_template = { + 'move':{ + 'header': [1, 20, 'text', _('Move')], + 'lines': [1, 0, 'text', _render("line.move_id.name or ''")], + 'totals': [1, 0, 'text', None]}, + 'name':{ + 'header': [1, 42, 'text', _('Name')], + 'lines': [1, 0, 'text', _render("line.name or ''")], + 'totals': [1, 0, 'text', None]}, + 'ref':{ + 'header': [1, 42, 'text', _('Reference')], + 'lines': [1, 0, 'text', _render("line.ref or ''")], + 'totals': [1, 0, 'text', None]}, + 'date':{ + 'header': [1, 13, 'text', _('Effective Date')], + 'lines': [1, 0, 'date', _render("datetime.strptime(line.date,'%Y-%m-%d')"), None, self.aml_cell_style_date], + 'totals': [1, 0, 'text', None]}, + 'period':{ + 'header': [1, 12, 'text', _('Period')], + 'lines': [1, 0, 'text', _render("line.period_id.code or ''")], + 'totals': [1, 0, 'text', None]}, + 'partner':{ + 'header': [1, 36, 'text', _('Partner')], + 'lines': [1, 0, 'text', _render("line.partner_id and line.partner_id.name or ''")], + 'totals': [1, 0, 'text', None]}, + 'partner_ref':{ + 'header': [1, 36, 'text', _('Partner Reference')], + 'lines': [1, 0, 'text', _render("line.partner_id and line.partner_id.ref or ''")], + 'totals': [1, 0, 'text', None]}, + 'account':{ + 'header': [1, 12, 'text', _('Account')], + 'lines': [1, 0, 'text', _render("line.account_id.code")], + 'totals': [1, 0, 'text', None]}, + 'date_maturity':{ + 'header': [1, 13, 'text', _('Maturity Date')], + 'lines': [1, 0, _render("line.date_maturity.val and 'date' or 'text'"), + _render("line.date_maturity.val and datetime.strptime(line.date_maturity,'%Y-%m-%d') or None"), + None, self.aml_cell_style_date], + 'totals': [1, 0, 'text', None]}, + 'debit':{ + 'header': [1, 18, 'text', _('Debit'), None, self.rh_cell_style_right], + 'lines': [1, 0, 'number', _render("line.debit"), None, self.aml_cell_style_decimal], + 'totals': [1, 0, 'number', None, _render("debit_formula"), self.rt_cell_style_decimal]}, + 'credit':{ + 'header': [1, 18, 'text', _('Credit'), None, self.rh_cell_style_right], + 'lines': [1, 0, 'number', _render("line.credit"), None, self.aml_cell_style_decimal], + 'totals': [1, 0, 'number', None, _render("credit_formula"), self.rt_cell_style_decimal]}, + 'balance':{ + 'header': [1, 18, 'text', _('Balance'), None, self.rh_cell_style_right], + 'lines': [1, 0, 'number', None, _render("bal_formula"), self.aml_cell_style_decimal], + 'totals': [1, 0, 'number', None, _render("bal_formula"), self.rt_cell_style_decimal]}, + 'reconcile':{ + 'header': [1, 12, 'text', _('Rec.'), None, self.rh_cell_style_center], + 'lines': [1, 0, 'text', _render("line.reconcile_id.name or ''"), None, self.aml_cell_style_center], + 'totals': [1, 0, 'text', None]}, + 'reconcile_partial':{ + 'header': [1, 12, 'text', _('Part. Rec.'), None, self.rh_cell_style_center], + 'lines': [1, 0, 'text', _render("line.reconcile_partial_id.name or ''"), None, self.aml_cell_style_center], + 'totals': [1, 0, 'text', None]}, + 'tax_code':{ + 'header': [1, 12, 'text', _('Tax Code'), None, self.rh_cell_style_center], + 'lines': [1, 0, 'text', _render("line.tax_code_id.code or ''"), None, self.aml_cell_style_center], + 'totals': [1, 0, 'text', None]}, + 'tax_amount':{ + 'header': [1, 18, 'text', _('Tax/Base Amount'), None, self.rh_cell_style_right], + 'lines': [1, 0, 'number', _render("line.tax_amount"), None, self.aml_cell_style_decimal], + 'totals': [1, 0, 'text', None]}, + } + + def generate_xls_report(self, _p, _xs, data, objects, wb): + + wanted_list = _p.wanted_list + + if 'balance' in wanted_list: + try: + debit_pos = wanted_list.index('debit') + credit_pos = wanted_list.index('credit') + except: + raise osv.except_osv(_('Customisation Error!'), + _("The 'Balance' field is a calculated XLS field requiring the presence of the 'Debit' and 'Credit' fields !")) + + report_name = objects[0]._description or objects[0]._name + ws = wb.add_sheet(report_name[:31]) + ws.panes_frozen = True + ws.remove_splits = True + ws.portrait = 0 # Landscape + ws.fit_width_to_pages = 1 + row_pos = 0 + + # set print header/footer + ws.header_str = self.xls_headers['standard'] + ws.footer_str = self.xls_footers['standard'] + + # Title + cell_style = xlwt.easyxf(_xs['xls_title']) + c_specs = [ + ('report_name', 1, 0, 'text', report_name), + ] + row_data = self.xls_row_template(c_specs, ['report_name']) + row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=cell_style) + row_pos += 1 + + # Column headers + c_specs = map(lambda x: self.render(x, self.col_specs_template, 'header', render_space={}), wanted_list) + row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs]) + row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.rh_cell_style, set_column_size=True) + ws.set_horz_split_pos(row_pos) + + # account move lines + for line in objects: + debit_cell = rowcol_to_cell(row_pos, debit_pos) + credit_cell = rowcol_to_cell(row_pos, credit_pos) + bal_formula = debit_cell + '-' + credit_cell + c_specs = map(lambda x: self.render(x, self.col_specs_template, 'lines'), wanted_list) + row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs]) + row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.aml_cell_style) + + # Totals + aml_cnt = len(objects) + debit_start = rowcol_to_cell(row_pos - aml_cnt, debit_pos) + debit_stop = rowcol_to_cell(row_pos - 1, debit_pos) + debit_formula = 'SUM(%s:%s)' %(debit_start, debit_stop) + credit_start = rowcol_to_cell(row_pos - aml_cnt, credit_pos) + credit_stop = rowcol_to_cell(row_pos - 1, credit_pos) + credit_formula = 'SUM(%s:%s)' %(credit_start, credit_stop) + debit_cell = rowcol_to_cell(row_pos, debit_pos) + credit_cell = rowcol_to_cell(row_pos, credit_pos) + bal_formula = debit_cell + '-' + credit_cell + c_specs = map(lambda x: self.render(x, self.col_specs_template, 'totals'), wanted_list) + row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs]) + row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.rt_cell_style_right) + +move_line_xls('report.move.line.list.xls', + 'account.move.line', + parser=move_line_xls_parser) + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/account_move_line_report_xls/report/move_line_list_xls.xml b/account_move_line_report_xls/report/move_line_list_xls.xml new file mode 100644 index 00000000..fcd4f00a --- /dev/null +++ b/account_move_line_report_xls/report/move_line_list_xls.xml @@ -0,0 +1,22 @@ + + + + + + Export Selected Lines + account.move.line + ir.actions.report.xml + move.line.list.xls + xls + + + + + Export Selected Lines + client_action_multi + + account.move.line + + + + From 2eee7ff1ac2c9cf6538f1be0707eff2880be9d41 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Thu, 31 Oct 2013 18:42:46 +0100 Subject: [PATCH 2/3] technical update --- account_move_line_report_xls/__init__.py | 4 ++-- account_move_line_report_xls/account_move_line.py | 7 ++----- account_move_line_report_xls/report/__init__.py | 2 +- .../report/move_line_list_xls.py | 11 +++++------ 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/account_move_line_report_xls/__init__.py b/account_move_line_report_xls/__init__.py index 6ad98d0c..728de535 100644 --- a/account_move_line_report_xls/__init__.py +++ b/account_move_line_report_xls/__init__.py @@ -20,5 +20,5 @@ # ############################################################################## -import account_move_line -import report +from . import account_move_line +from . import report diff --git a/account_move_line_report_xls/account_move_line.py b/account_move_line_report_xls/account_move_line.py index 2d12f38a..230720b1 100644 --- a/account_move_line_report_xls/account_move_line.py +++ b/account_move_line_report_xls/account_move_line.py @@ -20,9 +20,9 @@ # ############################################################################## -from osv import osv, fields +from openerp.osv import fields, orm -class account_move_line(osv.osv): +class account_move_line(orm.Model): _inherit = 'account.move.line' # override list in custom module to add/drop columns or change order @@ -31,6 +31,3 @@ class account_move_line(osv.osv): 'move', 'name', 'date', 'period', 'partner', 'account', 'date_maturity', 'debit', 'credit', 'balance', 'reconcile', 'reconcile_partial', ] - - -account_move_line() diff --git a/account_move_line_report_xls/report/__init__.py b/account_move_line_report_xls/report/__init__.py index cb01ef04..b4754155 100644 --- a/account_move_line_report_xls/report/__init__.py +++ b/account_move_line_report_xls/report/__init__.py @@ -20,4 +20,4 @@ # ############################################################################## -import move_line_list_xls +from . import move_line_list_xls diff --git a/account_move_line_report_xls/report/move_line_list_xls.py b/account_move_line_report_xls/report/move_line_list_xls.py index 9bc5b06c..5cb1e36e 100644 --- a/account_move_line_report_xls/report/move_line_list_xls.py +++ b/account_move_line_report_xls/report/move_line_list_xls.py @@ -23,12 +23,11 @@ import xlwt import time from datetime import datetime -from report import report_sxw -from report_xls.report_xls import report_xls -from report_xls.utils import rowcol_to_cell, _render -from account_move_line_report.report.move_line_list_print import move_line_list_print -from tools.translate import _ -import pooler +from openerp.report import report_sxw +from openerp.addons.report_xls.report_xls import report_xls +from openerp.addons.report_xls.utils import rowcol_to_cell, _render +from openerp.tools.translate import _ +from openerp import pooler import logging _logger = logging.getLogger(__name__) From d504361b0df3e3096422ebb67d454d5d71de3a10 Mon Sep 17 00:00:00 2001 From: Luc De Meyer Date: Wed, 18 Dec 2013 18:57:56 +0100 Subject: [PATCH 3/3] translations, extra fields, better inheritance support --- account_move_line_report_xls/__openerp__.py | 12 +- .../account_move_line.py | 21 +++- account_move_line_report_xls/i18n/fr.po | 111 ++++++++++++++++++ account_move_line_report_xls/i18n/nl.po | 111 ++++++++++++++++++ .../report/move_line_list_xls.py | 91 +++++++++----- .../static/src/img/icon.png | Bin 0 -> 11645 bytes 6 files changed, 314 insertions(+), 32 deletions(-) create mode 100644 account_move_line_report_xls/i18n/fr.po create mode 100644 account_move_line_report_xls/i18n/nl.po create mode 100644 account_move_line_report_xls/static/src/img/icon.png diff --git a/account_move_line_report_xls/__openerp__.py b/account_move_line_report_xls/__openerp__.py index cc24b208..366a9238 100644 --- a/account_move_line_report_xls/__openerp__.py +++ b/account_move_line_report_xls/__openerp__.py @@ -22,12 +22,20 @@ { 'name': 'Account Move Line XLS export', - 'version': '0.2', + 'version': '0.5', 'license': 'AGPL-3', 'author': 'Noviat', 'category' : 'Accounting & Finance', 'description': """ - This module adds a button on the journal items ('account.move.line') list view in order to export the selected lines. + +Journal Items Excel Export +========================== + +This module adds a button on the journal items ('account.move.line') list view in order to export the selected lines. + +If you are installing this module manually, you need also the module 'report_xls', that is located in: +https://launchpad.net/openerp-reporting-engines" + """, 'depends': ['account', 'report_xls'], 'demo_xml': [], diff --git a/account_move_line_report_xls/account_move_line.py b/account_move_line_report_xls/account_move_line.py index 230720b1..f63a833e 100644 --- a/account_move_line_report_xls/account_move_line.py +++ b/account_move_line_report_xls/account_move_line.py @@ -20,7 +20,9 @@ # ############################################################################## -from openerp.osv import fields, orm +from openerp.osv import orm +from openerp.addons.report_xls.utils import rowcol_to_cell, _render +from openerp.tools.translate import _ class account_move_line(orm.Model): _inherit = 'account.move.line' @@ -30,4 +32,21 @@ class account_move_line(orm.Model): return [ 'move', 'name', 'date', 'period', 'partner', 'account', 'date_maturity', 'debit', 'credit', 'balance', 'reconcile', 'reconcile_partial', + #'amount_currency', 'currency_name', ] + + # Change/Add Template entries + def _report_xls_template(self, cr, uid, context=None): + """ + Template updates, e.g. + + my_change = { + 'move':{ + 'header': [1, 20, 'text', _('My Move Title')], + 'lines': [1, 0, 'text', _render("line.move_id.name or ''")], + 'totals': [1, 0, 'text', None]}, + } + return my_change + """ + return {} + diff --git a/account_move_line_report_xls/i18n/fr.po b/account_move_line_report_xls/i18n/fr.po new file mode 100644 index 00000000..3e027d89 --- /dev/null +++ b/account_move_line_report_xls/i18n/fr.po @@ -0,0 +1,111 @@ +# French translation of OpenERP Server 6.1. +# This file contains the translation of the following modules: +# * account_move_line_report_xls +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.1\n" +"Report-Msgid-Bugs-To: support@noviat.be\n" +"POT-Creation-Date: 2013-11-23 16:11:12.706000\n" +"PO-Revision-Date: 2013-11-23 16:11:12.706000\n" +"Last-Translator: Luc De Meyer (Noviat nv/sa)\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Journal Items" +msgstr "Écritures comptables" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Entry" +msgstr "Écriture" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Name" +msgstr "Nom" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Reference" +msgstr "Référence" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Effective Date" +msgstr "Date" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Period" +msgstr "Période" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Partner" +msgstr "Partenaire" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Partner Reference" +msgstr "Réf. Partenaire" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Account" +msgstr "Compte" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Maturity Date" +msgstr "Date d'échéance" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Debit" +msgstr "Débit" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Credit" +msgstr "Crédit" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Balance" +msgstr "Solde" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Rec." +msgstr "Let." + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Part. Rec." +msgstr "Let. Part." + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Tax Code" +msgstr "Case TVA" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Tax/Base Amount" +msgstr "Montant TVA/Base" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Am. Currency" +msgstr "Montant devise" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Curr." +msgstr "Dev." + diff --git a/account_move_line_report_xls/i18n/nl.po b/account_move_line_report_xls/i18n/nl.po new file mode 100644 index 00000000..3b396580 --- /dev/null +++ b/account_move_line_report_xls/i18n/nl.po @@ -0,0 +1,111 @@ +# Dutch translation of OpenERP Server 6.1. +# This file contains the translation of the following modules: +# * account_move_line_report_xls +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.1\n" +"Report-Msgid-Bugs-To: support@noviat.be\n" +"POT-Creation-Date: 2013-11-23 16:11:12.702000\n" +"PO-Revision-Date: 2013-11-23 16:11:12.702000\n" +"Last-Translator: Luc De Meyer (Noviat nv/sa)\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Journal Items" +msgstr "Boekingsregels" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Entry" +msgstr "Boeking" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Name" +msgstr "Naam" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Reference" +msgstr "Referentie" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Effective Date" +msgstr "Datum" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Period" +msgstr "Periode" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Partner" +msgstr "Partner" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Partner Reference" +msgstr "Ref. Partner" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Account" +msgstr "Rekening" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Maturity Date" +msgstr "Vervaldatum" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Debit" +msgstr "Debet" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Credit" +msgstr "Credit" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Balance" +msgstr "Saldo" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Rec." +msgstr "Rec." + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Part. Rec." +msgstr "Rec. Part." + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Tax Code" +msgstr "BTW vak" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Tax/Base Amount" +msgstr "Bedrag BTW/Mvh" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Am. Currency" +msgstr "Bedrag valuta" + +#. module: account_move_line_report_xls +#: report:move.line.list.xls:0 +msgid "Curr." +msgstr "Val." + diff --git a/account_move_line_report_xls/report/move_line_list_xls.py b/account_move_line_report_xls/report/move_line_list_xls.py index 5cb1e36e..dbe3f340 100644 --- a/account_move_line_report_xls/report/move_line_list_xls.py +++ b/account_move_line_report_xls/report/move_line_list_xls.py @@ -23,26 +23,36 @@ import xlwt import time from datetime import datetime +from openerp.osv import orm from openerp.report import report_sxw from openerp.addons.report_xls.report_xls import report_xls from openerp.addons.report_xls.utils import rowcol_to_cell, _render -from openerp.tools.translate import _ +from openerp.tools.translate import translate, _ from openerp import pooler import logging _logger = logging.getLogger(__name__) +_ir_translation_name = 'move.line.list.xls' class move_line_xls_parser(report_sxw.rml_parse): def __init__(self, cr, uid, name, context): super(move_line_xls_parser, self).__init__(cr, uid, name, context=context) + move_obj = self.pool.get('account.move.line') self.context = context - wanted_list = self.pool.get('account.move.line')._report_xls_fields(cr, uid, context) + wanted_list = move_obj._report_xls_fields(cr, uid, context) + template_changes = move_obj._report_xls_template(cr, uid, context) self.localcontext.update({ 'datetime': datetime, 'wanted_list': wanted_list, + 'template_changes': template_changes, + '_': self._, }) + def _(self, src): + lang = self.context.get('lang', 'en_US') + return translate(self.cr, _ir_translation_name, 'report', lang, src) or src + class move_line_xls(report_xls): def __init__(self, name, table, rml=False, parser=False, header=True, store=False): @@ -70,86 +80,109 @@ class move_line_xls(report_xls): # XLS Template self.col_specs_template = { 'move':{ - 'header': [1, 20, 'text', _('Move')], + 'header': [1, 20, 'text', _render("_('Entry')")], 'lines': [1, 0, 'text', _render("line.move_id.name or ''")], 'totals': [1, 0, 'text', None]}, 'name':{ - 'header': [1, 42, 'text', _('Name')], + 'header': [1, 42, 'text', _render("_('Name')")], 'lines': [1, 0, 'text', _render("line.name or ''")], 'totals': [1, 0, 'text', None]}, 'ref':{ - 'header': [1, 42, 'text', _('Reference')], + 'header': [1, 42, 'text', _render("_('Reference')")], 'lines': [1, 0, 'text', _render("line.ref or ''")], 'totals': [1, 0, 'text', None]}, 'date':{ - 'header': [1, 13, 'text', _('Effective Date')], + 'header': [1, 13, 'text', _render("_('Effective Date')")], 'lines': [1, 0, 'date', _render("datetime.strptime(line.date,'%Y-%m-%d')"), None, self.aml_cell_style_date], 'totals': [1, 0, 'text', None]}, 'period':{ - 'header': [1, 12, 'text', _('Period')], - 'lines': [1, 0, 'text', _render("line.period_id.code or ''")], + 'header': [1, 12, 'text', _render("_('Period')")], + 'lines': [1, 0, 'text', _render("line.period_id.code or line.period_id.name")], 'totals': [1, 0, 'text', None]}, 'partner':{ - 'header': [1, 36, 'text', _('Partner')], + 'header': [1, 36, 'text', _render("_('Partner')")], 'lines': [1, 0, 'text', _render("line.partner_id and line.partner_id.name or ''")], 'totals': [1, 0, 'text', None]}, 'partner_ref':{ - 'header': [1, 36, 'text', _('Partner Reference')], + 'header': [1, 36, 'text', _render("_('Partner Reference')")], 'lines': [1, 0, 'text', _render("line.partner_id and line.partner_id.ref or ''")], 'totals': [1, 0, 'text', None]}, 'account':{ - 'header': [1, 12, 'text', _('Account')], + 'header': [1, 12, 'text', _render("_('Account')")], 'lines': [1, 0, 'text', _render("line.account_id.code")], 'totals': [1, 0, 'text', None]}, 'date_maturity':{ - 'header': [1, 13, 'text', _('Maturity Date')], + 'header': [1, 13, 'text', _render("_('Maturity Date')")], 'lines': [1, 0, _render("line.date_maturity.val and 'date' or 'text'"), _render("line.date_maturity.val and datetime.strptime(line.date_maturity,'%Y-%m-%d') or None"), None, self.aml_cell_style_date], 'totals': [1, 0, 'text', None]}, 'debit':{ - 'header': [1, 18, 'text', _('Debit'), None, self.rh_cell_style_right], + 'header': [1, 18, 'text', _render("_('Debit')"), None, self.rh_cell_style_right], 'lines': [1, 0, 'number', _render("line.debit"), None, self.aml_cell_style_decimal], 'totals': [1, 0, 'number', None, _render("debit_formula"), self.rt_cell_style_decimal]}, 'credit':{ - 'header': [1, 18, 'text', _('Credit'), None, self.rh_cell_style_right], + 'header': [1, 18, 'text', _render("_('Credit')"), None, self.rh_cell_style_right], 'lines': [1, 0, 'number', _render("line.credit"), None, self.aml_cell_style_decimal], 'totals': [1, 0, 'number', None, _render("credit_formula"), self.rt_cell_style_decimal]}, 'balance':{ - 'header': [1, 18, 'text', _('Balance'), None, self.rh_cell_style_right], + 'header': [1, 18, 'text', _render("_('Balance')"), None, self.rh_cell_style_right], 'lines': [1, 0, 'number', None, _render("bal_formula"), self.aml_cell_style_decimal], 'totals': [1, 0, 'number', None, _render("bal_formula"), self.rt_cell_style_decimal]}, 'reconcile':{ - 'header': [1, 12, 'text', _('Rec.'), None, self.rh_cell_style_center], + 'header': [1, 12, 'text', _render("_('Rec.')"), None, self.rh_cell_style_center], 'lines': [1, 0, 'text', _render("line.reconcile_id.name or ''"), None, self.aml_cell_style_center], 'totals': [1, 0, 'text', None]}, 'reconcile_partial':{ - 'header': [1, 12, 'text', _('Part. Rec.'), None, self.rh_cell_style_center], + 'header': [1, 12, 'text', _render("_('Part. Rec.')"), None, self.rh_cell_style_center], 'lines': [1, 0, 'text', _render("line.reconcile_partial_id.name or ''"), None, self.aml_cell_style_center], 'totals': [1, 0, 'text', None]}, 'tax_code':{ - 'header': [1, 12, 'text', _('Tax Code'), None, self.rh_cell_style_center], + 'header': [1, 12, 'text', _render("_('Tax Code')"), None, self.rh_cell_style_center], 'lines': [1, 0, 'text', _render("line.tax_code_id.code or ''"), None, self.aml_cell_style_center], 'totals': [1, 0, 'text', None]}, 'tax_amount':{ - 'header': [1, 18, 'text', _('Tax/Base Amount'), None, self.rh_cell_style_right], + 'header': [1, 18, 'text', _render("_('Tax/Base Amount')"), None, self.rh_cell_style_right], 'lines': [1, 0, 'number', _render("line.tax_amount"), None, self.aml_cell_style_decimal], 'totals': [1, 0, 'text', None]}, + 'amount_currency':{ + 'header': [1, 18, 'text', _render("_('Am. Currency')"), None, self.rh_cell_style_right], + 'lines': [1, 0, _render("line.amount_currency and 'number' or 'text'"), + _render("line.amount_currency or None"), + None, self.aml_cell_style_decimal], + 'totals': [1, 0, 'text', None]}, + 'currency_name':{ + 'header': [1, 6, 'text', _render("_('Curr.')"), None, self.rh_cell_style_center], + 'lines': [1, 0, 'text', _render("line.currency_id and line.currency_id.name or ''"), None, self.aml_cell_style_center], + 'totals': [1, 0, 'text', None]}, + 'journal': { + 'header': [1, 6, 'text', _('Journal')], + 'lines': [1, 0, 'text', _render("line.journal_id.code or ''")], + 'totals': [1, 0, 'text', None]}, + 'company_currency': { + 'header': [1, 6, 'text', _('Company currency')], + 'lines': [1, 0, 'text', _render("line.company_id.currency_id.name or ''")], + 'totals': [1, 0, 'text', None]}, + 'analytic_account': { + 'header': [1, 6, 'text', _('Analytic Account')], + 'lines': [1, 0, 'text', _render("line.analytic_account_id.code or ''")], + 'totals': [1, 0, 'text', None]}, } def generate_xls_report(self, _p, _xs, data, objects, wb): wanted_list = _p.wanted_list - - if 'balance' in wanted_list: - try: - debit_pos = wanted_list.index('debit') - credit_pos = wanted_list.index('credit') - except: - raise osv.except_osv(_('Customisation Error!'), - _("The 'Balance' field is a calculated XLS field requiring the presence of the 'Debit' and 'Credit' fields !")) + self.col_specs_template.update(_p.template_changes) + _ = _p._ - report_name = objects[0]._description or objects[0]._name + debit_pos = 'debit' in wanted_list and wanted_list.index('debit') + credit_pos = 'credit' in wanted_list and wanted_list.index('credit') + if not (credit_pos and debit_pos) and 'balance' in wanted_list: + raise orm.except_orm(_('Customisation Error!'), + _("The 'Balance' field is a calculated XLS field requiring the presence of the 'Debit' and 'Credit' fields !")) + + #report_name = objects[0]._description or objects[0]._name + report_name = _("Journal Items") ws = wb.add_sheet(report_name[:31]) ws.panes_frozen = True ws.remove_splits = True @@ -171,7 +204,7 @@ class move_line_xls(report_xls): row_pos += 1 # Column headers - c_specs = map(lambda x: self.render(x, self.col_specs_template, 'header', render_space={}), wanted_list) + c_specs = map(lambda x: self.render(x, self.col_specs_template, 'header', render_space={'_': _p._}), wanted_list) row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs]) row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.rh_cell_style, set_column_size=True) ws.set_horz_split_pos(row_pos) diff --git a/account_move_line_report_xls/static/src/img/icon.png b/account_move_line_report_xls/static/src/img/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b8a2fcdff9d1ae795a22cc4608a55d3c290b6e0c GIT binary patch literal 11645 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 Hu0mjfi6p;w literal 0 HcmV?d00001