生成 PDF 报告

重要

本教程是 开始 教程的扩展。确保您已经完成了该教程,并使用您构建的 estate 模块作为本教程中的练习基础。如果您想从一个干净的基础开始,请从 technical-training-solutions 存储库中获取 16.0-core 分支。

我们之前已经 介绍了 QWeb,在那里它被用来构建看板视图。现在我们将扩展QWeb的另一个主要用途:创建PDF报告。一个常见的业务需求是能够创建发送给客户和内部使用的文档。这些报告可以用来总结和展示信息,以有组织的模板方式支持业务的不同方面。Odoo还可以在我们的报告中添加公司的页眉和页脚,而只需付出最少的额外努力。

相关主题的文档可以在 QWeb模板QWeb报告 ,以及 Actions 参考中的 报告操作 ( ir.actions.report ) 部分找到。

文件结构

PDF报表的主要部分是其QWeb模板。通常还需要一个相应的 ir.actions.report 来将报表包含在模块的业务逻辑中。文件名或位置没有严格的规定,但这两个部分通常存储在模块目录顶层的 report 文件夹中的2个单独文件中。如果一个模块有多个或多个长报表模板,则通常会在不同的文件中按照报表的名称进行逻辑组织。所有报表的操作通常存储在同一个文件中,以 _reports.xml 结尾,不管它包含多少个报表。

因此,您的工作目录应该看起来像这样:

estate
├── models
│   ├── *.py
│   └── __init__.py
├── report
│   ├── estate_property_templates.xml
│   └── estate_property_reports.xml
├── security
│   └── ir.model.access.csv
├── views
│   └── *.xml
├── __init__.py
└── __manifest__.py

不要忘记将模板和操作视图所需的任何文件添加到您的 __manifest__.py 中。在这种情况下,您将希望将文件添加到 data 列表中,并记住清单中列出的文件是按顺序加载的!

基本报告

注解

目标:在本节结束时,我们将能够打印一个显示某个属性的所有报价的报告。

简单的PDF报告

在我们的房地产示例中,我们可以创建许多有用的报告。我们可以创建一个简单的报告,显示所有房产的报价。

报告数据

在我们开始之前,我们首先需要一些数据来填充我们的报告,否则这个教程将会很无聊。在创建报告时,您需要一些数据来测试您的报告代码,并检查结果的外观是否符合预期。最好使用能够涵盖大部分或所有预期用例的数据进行测试。我们简单报告的一个良好的代表性集合是:

  • 至少有3个属性,其中1个是”已售出”,1个是”已收到报价”,1个是”新的”。

  • 我们的“已售出”和“已收到报价”的房产至少需要2-3个报价

如果你还没有这样的数据集,你可以选择:

  • 完成 定义模块数据 教程(如果你还没有完成)并将额外的案例添加到你的演示数据中(你可能需要创建一个新的数据库来加载演示数据)。

  • 在数据库中手动创建数据。

  • 将此 数据文件 复制到您的房地产模块的新目录(data)中,并将 这些行 复制到您的 __manifest__.py 文件中(您可能需要创建一个新的数据库来加载演示数据)。

在继续之前,请浏览您数据库中的数据,并确保您的数据符合预期。当然,您可以在编写报告代码后添加数据,但这样您将无法逐步测试编写代码的部分。对于复杂的报告,在长期运行中,这可能会使检查错误和调试代码更加困难。

最小模板

一个最小可行的模板可以在 报告模板 文档的 “Minimal viable template” 部分中查看。我们可以修改这个示例来构建我们的最小房产报价模板文件:

<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
    <template id="report_property_offers">
        <t t-foreach="docs" t-as="property">
            <t t-call="web.html_container">
                <t t-call="web.external_layout">
                    <div class="page">
                        <h2>
                            <span t-field="property.name"/>
                        </h2>
                        <div>
                            <strong>Expected Price: </strong>
                            <span t-field="property.expected_price"/>
                        </div>
                        <table class="table">
                            <thead>
                                <tr>
                                    <th>Price</th>
                                </tr>
                            </thead>
                            <tbody>
                                <t t-set="offers" t-value="property.mapped('offer_ids')"/>
                                <tr t-foreach="offers" t-as="offer">
                                    <td>
                                        <span t-field="offer.price"/>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </t>
            </t>
        </t>
    </template>
</odoo>

我们文件中的大部分Odoo特定(即非HTML)项目在最小可行模板部分中有解释。我们模板中的一些其他功能包括:

  • 使用 class="table" 属性,使我们的表格具有一些漂亮的格式。您可以在报告模板中使用 Twitter Bootstrap(在本例中我们使用了它的表格类)和 Font Awesome(用于添加图标)类。

  • 使用 t-sett-valuet-foreacht-as ,以便我们可以循环遍历所有的 offer_ids

如果您已经熟悉网站模板引擎,那么QWeb指令(即 t- 命令)可能不需要太多解释,您可以直接查看其 文档 并跳转到下一小节。

否则,建议您阅读更多关于它们的信息( Wikipedia 提供了一个很好的高级 描述),但总体思想是QWeb提供了根据Odoo数据和简单命令动态生成Web代码的能力。也就是说,QWeb可以访问记录集数据(和方法)并处理设置和访问临时变量等简单编程操作。例如,在上面的例子中:

  • t-set 创建一个临时变量叫做 “offers”,它的值由 t-value 设置为当前 estate.property 记录集的 offer_ids

  • The t-foreach and t-as usage is the equivalent to the Python:

for offer in offers:

报表操作

现在我们有了一个模板,我们需要通过``ir.actions.report``在我们的应用程序中使其可访问。``ir.actions.report``的一个实际示例在这里<https://github.com/odoo/odoo/blob/0e12fa135882cd5095dbf15fe2f64231c6a84336/addons/event/report/event_event_reports.xml#L20-L30>`__ 对应于`这个模板<https://github.com/odoo/odoo/blob/0e12fa135882cd5095dbf15fe2f64231c6a84336/addons/event/report/event_event_templates.xml#L5>`__。 其内容在:ref:`文档<reference/actions/report>`中都有解释。

一个 ir.actions.report 主要通过模型视图的打印菜单使用。在实际示例中, binding_model_id 指定了报表应该显示哪个模型的视图,Odoo 会自动为您添加它。报表操作的另一个常见用例是将其链接到按钮,就像我们在 第十章:准备好行动了吗? 中学到的那样。这对于只在特定条件下有意义的报表非常方便。例如,如果我们想制作一个“最终销售”报表,那么我们可以将其链接到一个“打印销售信息”按钮,该按钮仅在属性为“已售出”时在表单视图中显示。

打印菜单按钮

你可能已经注意到或者想知道为什么我们的报告模板要循环遍历记录集。当我们的模板传递多个记录时,它可以为所有记录生成一个PDF报告。在列表视图中选择多个记录并使用打印菜单可以演示这一点。

生成报告

最后,您现在知道在哪里创建文件以及文件内容应该如何。祝您制作报告愉快!

Exercise

生成报告。

  • 将最小模板子部分的房产报告属性添加到房产视图的打印菜单中。

  • 通过添加更多数据来改进报告。请参考本节的 目标 ,了解可以添加哪些附加数据,并随意添加更多内容。

  • 奖励:通过添加一些逻辑,使报告更加灵活,当某个属性上没有报价时,我们不创建表格,而是写一些关于还没有报价的内容。提示:您需要使用 t-ift-else

请记得检查您的PDF报告是否符合预期的数据。

子模板

注解

目标:在本节结束时,我们将拥有一个在两个报告中使用的子模板。

使用子模板的报告

使用子模板有两个主要原因。一是在处理特别长或复杂的模板时,使代码更易于阅读。另一个原因是尽可能地重用代码。我们的简单物业报告很有用,但列出物业报价信息可以用于不止一个报告模板。一个例子是列出一个销售员所有物业报价的报告。

看看你是否能通过阅读 文档 或查看一个 示例 <https://github.com/odoo/odoo/blob/0e12fa135882cd5095dbf15fe2f64231c6a84336/addons/portal/static/src/xml/portal_chatter.xml#L147-L160> __来理解如何调用子模板(请记住,无论是报表还是Odoo中的视图,QWeb都使用相同的控制流程。)

Exercise

创建并使用子模板。

  • 将报价单的表格部分拆分到单独的模板中。记得在此之后检查原始报告是否仍然可以正确打印。

  • res.users 添加一个新的报表,允许您打印在其表单视图中可见的所有房地产属性(即在“设置”应用程序中)。在同一报表中包括每个销售员的属性的报价。提示:由于此情况下的 binding_model_id 不在房地产模块中,您需要使用 ref="base.model_res_users"

    您的最终结果应该与本节的 目标 中的图像类似。

请记得检查您的报表是否符合预期的数据!

报告继承

注解

Goal: at the end of this section, we will inherit the property report in the estate_account module.

一个继承的报告

在QWeb中,继承使用与 视图继承 相同的 xpath 元素。但是,QWeb模板以不同的方式引用其父模板。只需将 inherit_id 属性添加到 template 元素,并将其设置为 module.parent_template_id,就可以更容易地实现。

我们没有向 estate_account 中的任何房地产模型添加新字段,但我们仍然可以向现有的房地产报告中添加信息。例如,我们知道任何“已售出”的房产已经有了相应的发票,因此我们可以将这些信息添加到我们的报告中。

Exercise

继承一个报告。

  • 扩展财产报告,包括一些关于发票的信息。您可以查看本节的 目标 以获取灵感(即在财产完成时打印一行,否则不打印任何内容)。

再次提醒,记得检查报告与数据是否符合预期!

附加功能

所有以下额外功能在 QWeb报告 文档中有进一步描述,包括如何实现每一个功能。

翻译

我们都知道Odoo可以通过自动化和手动翻译来支持多种语言。QWeb报告也不例外!请注意,如果模板的文本内容中存在不必要的空格,尤其是前导空格,有时翻译可能无法正常工作,请尽可能避免它们。

报告是网页

你可能已经听腻了QWeb创建HTML的说法,但我们还是要再说一遍!使用QWeb编写报告的一个很棒的特性是它们可以在Web浏览器中查看。如果您想嵌入一个超链接,以便导航到特定的报告,这将非常有用。请注意,通常的安全检查仍将适用,以防止未经授权的用户访问报告。

条形码

Odoo 内置了条形码图像创建器,可以将条形码嵌入到您的报告中。请查看相应的 code 以查看所有支持的条形码类型。