Odoo报表动作源码研究 - xiaohao0576/odoo-doc GitHub Wiki

报表动作模型

  • 源码文件: odoo/addons/base/models/ir_actions_report.py
  • 搜索关键字: _name = 'ir.actions.report'
  • 点击查看源码

报表类型

    report_type = fields.Selection([
        ('qweb-html', 'HTML'),
        ('qweb-pdf', 'PDF'),
        ('qweb-text', 'Text'),
    ], required=True, default='qweb-pdf',

渲染报表函数

点击查看源码

    @api.model
    def _render(self, report_ref, res_ids, data=None):
        report = self._get_report(report_ref)
        report_type = report.report_type.lower().replace('-', '_')
        render_func = getattr(self, '_render_' + report_type, None)
        if not render_func:
            return None
        return render_func(report_ref, res_ids, data=data)
  • 如果报表类型是qweb-pdf,这个函数就会调用_render_qweb_pdf函数,点击查看源码
  • 如果报表类型是qweb-html,这个函数就会调用_render_qweb_html函数
  • 如果报表类型是qweb-text,这个函数就会调用_render_qweb_text函数

_render_qweb_pdf函数

这个函数会调用以下两个重要的函数,第一个函数是_pre_render_qweb_pdf,用于实际生成一组单页的pdf的内容。

然后再调用_merge_pdfs函数,把单页的pdf组合成一个pdf文档,并返回二进制pdf内容

_pre_render_qweb_pdf函数

这个函数主要是调用_render_qweb_pdf_prepare_streams

_render_qweb_pdf_prepare_streams函数

  1. 调用_render_qweb_html函数生成html
  2. 调用_prepare_html获得bodies, html_ids, header, footer, specific_paperformat_args
  3. 调用_run_wkhtmltopdf,把html网页转化为pdf文件
html = self.with_context(**additional_context)._render_qweb_html(report_ref, all_res_ids_wo_stream, data=data)[0]

bodies, html_ids, header, footer, specific_paperformat_args = report_sudo.with_context(**additional_context)._prepare_html(html, report_model=report_sudo.model)
            pdf_content = self._run_wkhtmltopdf(
                bodies,
                report_ref=report_ref,
                header=header,
                footer=footer,
                landscape=self._context.get('landscape'),
                specific_paperformat_args=specific_paperformat_args,
                set_viewport_size=self._context.get('set_viewport_size'),
            )

_run_wkhtmltopdf函数

  1. 获取页面尺寸定义
  2. 调用_build_wkhtmltopdf_args函数,准备wkhtmltopdf的命令行参数
  3. 在子进程运行wkhtmltopdf命令
        paperformat_id = self._get_report(report_ref).get_paperformat() if report_ref else self.get_paperformat()

        # Build the base command args for wkhtmltopdf bin
        command_args = self._build_wkhtmltopdf_args(
            paperformat_id,
            landscape,
            specific_paperformat_args=specific_paperformat_args,
            set_viewport_size=set_viewport_size)
wkhtmltopdf = [_get_wkhtmltopdf_bin()] + command_args + files_command_args + paths + [pdf_report_path]
process = subprocess.Popen(wkhtmltopdf, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
_out, err = process.communicate()

_build_wkhtmltopdf_args函数

根据paperformat定义的页面规格,生成wkhtmltopdf需要的命令行参数,点击查看源码

其它有用的函数

  1. _run_wkhtmltoimage函数可以把html转化成jpg或者png图片,点击查看源码
  2. barcode可以生成各种条形码或者二维码,点击查看源码

在xml template中调用barcode功能, https://www.odoo.com/documentation/18.0/developer/reference/backend/reports.html#barcodes

点击查看源码

查看pdf报告的HTML源码

pdf报告也是HTML页面,可以通过网址直接打开HTML页面或者PDF报告

https://www.odoo.com/documentation/18.0/developer/reference/backend/reports.html#reports-are-web-pages

比如: https://mydomain.odoo.com/report/html/sale.report_saleorder_pro_forma/93 https://mydomain.odoo.com/report/html/sale.report_saleorder_pro_forma/93

点击查看源码

    @http.route([
        '/report/<converter>/<reportname>',
        '/report/<converter>/<reportname>/<docids>',
    ], type='http', auth='user', website=True, readonly=True)
    def report_routes(self, reportname, docids=None, converter=None, **data):
        report = request.env['ir.actions.report']
        context = dict(request.env.context)

        if docids:
            docids = [int(i) for i in docids.split(',') if i.isdigit()]
        if data.get('options'):
            data.update(json.loads(data.pop('options')))
        if data.get('context'):
            data['context'] = json.loads(data['context'])
            context.update(data['context'])
        if converter == 'html':
            html = report.with_context(context)._render_qweb_html(reportname, docids, data=data)[0]
            return request.make_response(html)
        elif converter == 'pdf':
            pdf = report.with_context(context)._render_qweb_pdf(reportname, 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(reportname, 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)
⚠️ **GitHub.com Fallback** ⚠️