From ffa475afcd2b0b2504a0a0947b2368c130d73815 Mon Sep 17 00:00:00 2001 From: Simon Lejeune Date: Fri, 21 Feb 2014 17:33:20 +0100 Subject: [PATCH] [IMP] Added the possibility to define ultra-specific reports outputing any king of file. These reports are of type 'controller' because they redirects to a controller that must returns a response containing the http headers 'content-type' and 'content-disposition'. The route for this controller is specified in the report_file field. Added an XLS version of the tax report for the POC (testable by setting 'report_vat' type to controller and setting '/report/account.report_vat_xls' in the 'report_file' field). bzr revid: sle@openerp.com-20140221163320-g5ouoywsuduoi0qe --- addons/account/report/report_vat.py | 44 ++++++++++++ addons/account/views/report_vat.xml | 2 +- addons/report/controllers/main.py | 67 ++++++++++++------- addons/report/models/report.py | 1 + .../report/static/src/js/qwebactionmanager.js | 35 +++++++--- 5 files changed, 114 insertions(+), 35 deletions(-) diff --git a/addons/account/report/report_vat.py b/addons/account/report/report_vat.py index 2d31a5c7a70..236e2ffaac2 100644 --- a/addons/account/report/report_vat.py +++ b/addons/account/report/report_vat.py @@ -22,6 +22,11 @@ from openerp.addons.web import http from openerp.addons.web.http import request from common_report_header import common_report_header +try: + import cStringIO as StringIO +except ImportError: + import StringIO +import xlwt class tax_report(http.Controller, common_report_header): @@ -224,4 +229,43 @@ class tax_report(http.Controller, common_report_header): return result_accounts + @http.route(['/report/account.report_vat_xls'], type='http', auth='user', website=True, multilang=True) + def report_account_tax_xls(self, **data): + report_obj = request.registry['report'] + self.cr, self.uid, self.pool = request.cr, request.uid, request.registry + + data = report_obj.eval_params(data) + + res = {} + self.period_ids = [] + period_obj = self.pool.get('account.period') + self.display_detail = data['form']['display_detail'] + res['periods'] = '' + res['fiscalyear'] = data['form'].get('fiscalyear_id', False) + + if data['form'].get('period_from', False) and data['form'].get('period_to', False): + self.period_ids = period_obj.build_ctx_periods(self.cr, self.uid, data['form']['period_from'], data['form']['period_to']) + + content = '' + lines = self._get_lines(self._get_basedon(data), company_id=data['form']['company_id']) + + if lines: + xls = StringIO.StringIO() + xls_workbook = xlwt.Workbook() + vat_sheet = xls_workbook.add_sheet('report_vat') + + for x in range(0, len(lines)): + for y in range(0, len(lines[0])): + vat_sheet.write(x, y, lines[x].values()[y]) + + xls_workbook.save(xls) + xls.seek(0) + content = xls.read() + + response = request.make_response(content, headers=[ + ('Content-Type', 'application/vnd.ms-excel'), + ('Content-Disposition', 'attachment; filename=report_vat.xls;') + ]) + return response + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/account/views/report_vat.xml b/addons/account/views/report_vat.xml index 4ef1fb54aec..03664045ef4 100644 --- a/addons/account/views/report_vat.xml +++ b/addons/account/views/report_vat.xml @@ -7,7 +7,7 @@

Tax Statement

-
+
Chart of Tax:

diff --git a/addons/report/controllers/main.py b/addons/report/controllers/main.py index 724d3040e36..df68fce1291 100644 --- a/addons/report/controllers/main.py +++ b/addons/report/controllers/main.py @@ -83,11 +83,18 @@ class Report(http.Controller): 'docs': docs, } - return request.registry['report'].render(request.cr, request.uid, [], report.report_file, + return request.registry['report'].render(request.cr, request.uid, [], report.report_name, docargs, context=request.context) @http.route(['/report/pdf/'], type='http', auth="user", website=True) def report_pdf(self, path=None, landscape=False, **post): + """Route converting any reports to pdf. It will get the html-rendered report, extract + header, page and footer in order to prepare minimal html pages that will be further passed + to wkhtmltopdf. + + :param path: URL of the report (e.g. /report/account.report_invoice/1) + :returns: a response with 'application/pdf' headers and the pdf as content + """ cr, uid, context = request.cr, request.uid, request.context # Get the report we are working on. @@ -136,14 +143,14 @@ class Report(http.Controller): paperformat = report.paperformat_id # Get the html report. - html = self._get_url_content('/' + path, post) + html = self._get_url_content('/' + path, post)[0] # Get some css and script in order to build a minimal html page for the report. # This page will later be sent to wkhtmltopdf. - css = self._get_url_content('/report/static/src/css/reset.min.css') - css += self._get_url_content('/web/static/lib/bootstrap/css/bootstrap.css') - css += self._get_url_content('/website/static/src/css/website.css') - subst = self._get_url_content('/report/static/src/js/subst.js') + css = self._get_url_content('/report/static/src/css/reset.min.css')[0] + css += self._get_url_content('/web/static/lib/bootstrap/css/bootstrap.css')[0] + css += self._get_url_content('/website/static/src/css/website.css')[0] + subst = self._get_url_content('/report/static/src/js/subst.js')[0] headerhtml = [] contenthtml = [] @@ -240,7 +247,7 @@ class Report(http.Controller): except UnicodeDecodeError: pass - return content + return tuple([content, response.headers]) def _generate_wkhtml_pdf(self, headers, footers, bodies, landscape, paperformat, spec_paperformat_args=None, save_in_attachment=None): @@ -440,31 +447,19 @@ class Report(http.Controller): merged.close() return content - @http.route('/report/downloadpdf/', type='http', auth="user") - def report_pdf_attachment(self, data, token): - """This function is only used by 'qwebactionmanager.js' in order to trigger the download of - a pdf report. - - :param data: The JSON.stringified report internal url - :returns: Response with a filetoken cookie and an attachment header - """ - url = simplejson.loads(data) - pdf = self._get_url_content(url) - response = self._make_pdf_response(pdf) - response.set_cookie('fileToken', token) - response.headers.add('Content-Disposition', 'attachment; filename=report.pdf;') - return response - @http.route(['/report/barcode', '/report/barcode//'], type='http', auth="user") def barcode(self, type, value, width=300, height=50): """Contoller able to render barcode images thanks to reportlab. - Sample: + Samples: + + :param type: Accepted types: 'Codabar', 'Code11', 'Code128', 'EAN13', 'EAN8', 'Extended39', 'Extended93', 'FIM', 'I2of5', 'MSI', 'POSTNET', 'QR', 'Standard39', 'Standard93', 'UPCA', 'USPS_4State' """ try: + width, height = int(width), int(height) barcode = createBarcodeImageInMemory( type, value=value, format='png', width=width, height=height ) @@ -474,3 +469,29 @@ class Report(http.Controller): raise exceptions.HTTPException(description='Please upgrade reportlab to at least 3.0.') return request.make_response(barcode, headers=[('Content-Type', 'image/png')]) + + @http.route('/report/download/', type='http', auth="user") + def report_attachment(self, data, token): + """This function is only used by 'qwebactionmanager.js' in order to trigger the download of + a report. + + :param data: The JSON.stringified report internal url + :returns: Response with a filetoken cookie and an attachment header + """ + requestcontent = simplejson.loads(data) + url, type = requestcontent[0], requestcontent[1] + file, fileheaders = self._get_url_content(url) + + if type == 'qweb-pdf': + response = self._make_pdf_response(file) + response.headers.add('Content-Disposition', 'attachment; filename=report.pdf;') + elif type == 'controller': + response = request.make_response(file) + response.headers.add('Content-Disposition', fileheaders['Content-Disposition']) + response.headers.add('Content-Type', fileheaders['Content-Type']) + else: + return + + response.headers.add('Content-Length', len(file)) + response.set_cookie('fileToken', token) + return response diff --git a/addons/report/models/report.py b/addons/report/models/report.py index 86b4c69c2a1..e54e2b9a6a2 100644 --- a/addons/report/models/report.py +++ b/addons/report/models/report.py @@ -241,6 +241,7 @@ class report(osv.Model): 'type': 'ir.actions.report.xml', 'report_name': report.report_name, 'report_type': report.report_type, + 'report_file': report.report_file, } if datas: diff --git a/addons/report/static/src/js/qwebactionmanager.js b/addons/report/static/src/js/qwebactionmanager.js index 37f5489ab37..615b3677c30 100644 --- a/addons/report/static/src/js/qwebactionmanager.js +++ b/addons/report/static/src/js/qwebactionmanager.js @@ -9,13 +9,22 @@ openerp.report = function(instance) { action.context = instance.web.pyeval.eval('contexts',eval_contexts); // QWeb reports - if ('report_type' in action && (action.report_type == 'qweb-html' || action.report_type == 'qweb-pdf')) { - var report_url = ''; - - if (action.report_type == 'qweb-html') { - report_url = '/report/' + action.report_name; - } else { - report_url = '/report/pdf/report/' + action.report_name; + if ('report_type' in action && (action.report_type == 'qweb-html' || action.report_type == 'qweb-pdf' || action.report_type == 'controller')) { + + var report_url = '' + switch (action.report_type) { + case 'qweb-html': + report_url = '/report/' + action.report_name; + break; + case 'qweb-pdf': + report_url = '/report/pdf/report/' + action.report_name; + break; + case 'controller': + report_url = action.report_file; + break; + default: + report_url = '/report/' + action.report_name; + break; } // single/multiple id(s): no query string @@ -27,7 +36,7 @@ openerp.report = function(instance) { } else { _.each(action.datas.form, function(value, key) { // will be erased when all wizards are rewritten - if(key.substring(0, 12) === 'used_context') { + if (key.substring(0, 12) === 'used_context') { delete action.datas.form[key]; } @@ -43,11 +52,15 @@ openerp.report = function(instance) { instance.web.unblockUI(); return; } else { - // Trigger the download of the pdf report + // Trigger the download of the pdf/custom controller report var c = openerp.webclient.crashmanager; + var response = new Array() + response[0] = report_url + response[1] = action.report_type + this.session.get_file({ - url: '/report/downloadpdf', - data: {data: JSON.stringify(report_url)}, + url: '/report/download', + data: {data: JSON.stringify(response)}, complete: openerp.web.unblockUI, error: c.rpc_error.bind(c) });