diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index ff4807af25c..76039c41e2d 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1575,6 +1575,10 @@ class ReportController(http.Controller): pdf = report.with_context(context).render_qweb_pdf(docids, data=data)[0] pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))] return request.make_response(pdf, headers=pdfhttpheaders) + elif converter == 'text': + text = report.with_context(context).render_qweb_text(docids, data=data)[0] + texthttpheaders = [('Content-Type', 'text/plain'), ('Content-Length', len(text))] + return request.make_response(text, headers=texthttpheaders) else: raise werkzeug.exceptions.HTTPException(description='Converter %s not implemented.' % converter) @@ -1614,8 +1618,12 @@ class ReportController(http.Controller): requestcontent = json.loads(data) url, type = requestcontent[0], requestcontent[1] try: - if type == 'qweb-pdf': - reportname = url.split('/report/pdf/')[1].split('?')[0] + if type in ['qweb-pdf', 'qweb-text']: + converter = 'pdf' if type == 'qweb-pdf' else 'text' + extension = 'pdf' if type == 'qweb-pdf' else 'txt' + + pattern = '/report/pdf/' if type == 'qweb-pdf' else '/report/text/' + reportname = url.split(pattern)[1].split('?')[0] docids = None if '/' in reportname: @@ -1623,20 +1631,21 @@ class ReportController(http.Controller): if docids: # Generic report: - response = self.report_routes(reportname, docids=docids, converter='pdf') + response = self.report_routes(reportname, docids=docids, converter=converter) else: # Particular report: data = url_decode(url.split('?')[1]).items() # decoding the args represented in JSON - response = self.report_routes(reportname, converter='pdf', **dict(data)) + response = self.report_routes(reportname, converter=converter, **dict(data)) report = request.env['ir.actions.report']._get_report_from_name(reportname) - filename = "%s.%s" % (report.name, "pdf") + filename = "%s.%s" % (report.name, extension) + if docids: ids = [int(x) for x in docids.split(",")] obj = request.env[report.model].browse(ids) if report.print_report_name and not len(obj) > 1: report_name = safe_eval(report.print_report_name, {'object': obj, 'time': time}) - filename = "%s.%s" % (report_name, "pdf") + filename = "%s.%s" % (report_name, extension) response.headers.add('Content-Disposition', content_disposition(filename)) response.set_cookie('fileToken', token) return response diff --git a/addons/web/static/src/js/chrome/action_manager_report.js b/addons/web/static/src/js/chrome/action_manager_report.js index 8975fea2628..60f23de9b74 100644 --- a/addons/web/static/src/js/chrome/action_manager_report.js +++ b/addons/web/static/src/js/chrome/action_manager_report.js @@ -46,10 +46,11 @@ ActionManager.include({ _downloadReport: function (url) { framework.blockUI(); var def = $.Deferred(); + var type = 'qweb-' + url.split('/')[2]; var blocked = !session.get_file({ url: '/report/download', data: { - data: JSON.stringify([url, 'qweb-pdf']), + data: JSON.stringify([url, type]), }, success: def.resolve.bind(def), error: function () { @@ -69,6 +70,28 @@ ActionManager.include({ } return def; }, + + /** + * Launch download action of the report + * + * @private + * @param {Object} action the description of the action to execute + * @param {Object} options @see doAction for details + * @returns {Deferred} resolved when the action has been executed + */ + _triggerDownload: function (action, options, type){ + var self = this; + var processedActions = []; + var currentAction = action; + var defs = []; + do { + var reportUrls = self._makeReportUrls(currentAction); + defs.push(self._downloadReport(reportUrls[type])); + processedActions.push(currentAction); + currentAction = currentAction.next_report_to_generate; + } while (currentAction && !_.contains(processedActions, currentAction)); + return $.when.apply($, defs).done(options.on_close); + }, /** * Executes actions of type 'ir.actions.report'. * @@ -92,21 +115,14 @@ ActionManager.include({ if (state === 'upgrade' || state === 'ok') { // trigger the download of the PDF report - var processedActions = []; - var currentAction = action; - var defs = []; - do { - var reportUrls = self._makeReportUrls(currentAction); - defs.push(self._downloadReport(reportUrls.pdf)); - processedActions.push(currentAction); - currentAction = currentAction.next_report_to_generate; - } while (currentAction && !_.contains(processedActions, currentAction)); - return $.when.apply($, defs).done(options.on_close); + return self._triggerDownload(action, options, 'pdf'); } else { // open the report in the client action if generating the PDF is not possible return self._executeReportClientAction(action, options); } }); + } else if (action.report_type === 'qweb-text') { + return self._triggerDownload(action, options, 'text'); } else { console.error("The ActionManager can't handle reports of type " + action.report_type, action); @@ -160,6 +176,7 @@ ActionManager.include({ var reportUrls = { html: '/report/html/' + action.report_name, pdf: '/report/pdf/' + action.report_name, + text: '/report/text/' + action.report_name, }; // We may have to build a query string with `action.data`. It's the place // were report's using a wizard to customize the output traditionally put @@ -182,5 +199,4 @@ ActionManager.include({ return reportUrls; }, }); - }); diff --git a/odoo/addons/base/models/ir_actions_report.py b/odoo/addons/base/models/ir_actions_report.py index 0658f5250a9..28bd60beb74 100644 --- a/odoo/addons/base/models/ir_actions_report.py +++ b/odoo/addons/base/models/ir_actions_report.py @@ -82,10 +82,15 @@ class IrActionsReport(models.Model): binding_type = fields.Selection(default='report') model = fields.Char(required=True) - report_type = fields.Selection([('qweb-html', 'HTML'), ('qweb-pdf', 'PDF')], required=True, default='qweb-pdf', - help='The type of the report that will be rendered, each one having its own rendering method.' - 'HTML means the report will be opened directly in your browser' - 'PDF means the report will be rendered using Wkhtmltopdf and downloaded by the user.') + report_type = fields.Selection([ + ('qweb-html', 'HTML'), + ('qweb-pdf', 'PDF'), + ('qweb-text', 'Text'), + ], required=True, default='qweb-pdf', + help='The type of the report that will be rendered, each one having its own' + ' rendering method. HTML means the report will be opened directly in your' + ' browser PDF means the report will be rendered using Wkhtmltopdf and' + ' downloaded by the user.') report_name = fields.Char(string='Template Name', required=True, help="For QWeb reports, name of the template used in the rendering. The method 'render_html' of the model 'report.template_name' will be called (if any) to give the html. For RML reports, this is the LocalService name.") report_file = fields.Char(string='Report File', required=False, readonly=False, store=True, @@ -419,8 +424,7 @@ class IrActionsReport(models.Model): the field report_name. """ report_obj = self.env['ir.actions.report'] - qwebtypes = ['qweb-pdf', 'qweb-html'] - conditions = [('report_type', 'in', qwebtypes), ('report_name', '=', report_name)] + conditions = [('report_name', '=', report_name)] context = self.env['res.users'].context_get() return report_obj.with_context(context).search(conditions, limit=1) @@ -648,10 +652,20 @@ class IrActionsReport(models.Model): return self._post_pdf(save_in_attachment, pdf_content=pdf_content, res_ids=html_ids), 'pdf' return pdf_content, 'pdf' + @api.model + def render_qweb_text(self, docids, data=None): + data = self._get_rendering_context(docids, data) + return self.render_template(self.report_name, data), 'text' + @api.model def render_qweb_html(self, docids, data=None): """This method generates and returns html version of a report. """ + data = self._get_rendering_context(docids, data) + return self.render_template(self.report_name, data), 'html' + + @api.model + def _get_rendering_context(self, docids, data): # If the report is using a custom model to render its html, we must use it. # Otherwise, fallback on the generic html rendering. report_model_name = 'report.%s' % self.report_name @@ -666,7 +680,7 @@ class IrActionsReport(models.Model): 'doc_model': self.model, 'docs': docs, } - return self.render_template(self.report_name, data), 'html' + return data @api.multi def render(self, res_ids, data=None):