简介:项目实际开发过程中,有时会面临将前端数据下载生成报表的需求,虽然也可以通过导出数据再生成相应的报表,但是这样操作起来太复杂。odoo自身集成了将数据直接生成pdf格式文档的功能,而且可以通过自定义模板生成各种样式的报表。
1. odoo的报表展示
选择相应记录数据,打印动作按钮下会有相应的动作按钮
PDF报表展示
2. odoo14定义打印报表动作
1. 新建report目录-新建报表xml文件material_storage_pdf.xml
2. 定义xml文件报表参数参数
ir.actions.report报表属性
- name:打印动作按钮下的报表名字
- model:你的报表相关的模型,也就是说是你下载pdf中,pdf中数据的来源
- report_type:PDF报表的qweb-pdf 或HTML的 qweb-html,就是下载的报表类型
- groups_id:允许浏览/使用当前报表的组的Many2many 字段
- attachment_use:若设置为True, 使用 attachment表达式所生成的名称存储为附件的报表;如果需要仅生成一次报表可以使用它 (例如出于法律原因)
- attachment:定义报表名称的python 表达式;记录可作为 object变量访问
- paperformat_id:定义纸张格式
<record id="material_storage_report_pdf2" model="ir.actions.report">
<field name="name">物料标识卡</field>
<field name="model">material.storage</field>
<!--报告类型:pdf或html-->
<field name="report_type">qweb-html</field>
<!--报告名字:module_name.自定义报表模板名称-->
<field name="report_name">quality_inspection.material_storage_pdf2</field>
<field name="report_file">quality_inspection.material_storage_pdf2</field>
<!--指定报表使用的纸张格式,默认使用公司的格式,这里指定设置的格式-->
<field name="paperformat_id" ref="material_storage_pdf2_paper"/>
<!--pdf报告名字,引用记录的编号字段-->
<field name="print_report_name">'物料标识卡'+ str(object.name)</field>
<!-- 是否适用附件功能 优点第2+次打印直接读取附件 速度更快 | 缺点由于存储了附件 报表格式或内容改变后 下载依旧是第一次的样子 -->
<field name="attachment_use">False</field>
<!--绑定的模型,这里指定你要关联的模型-->
<field name="binding_model_id" ref="model_material_storage"/>
<!--绑定的类型-->
<field name="binding_type">report</field>
</record>
3. 定义报表模板
- 报表模板在template标签中定义,定义的id的值不是随便定义的,要和report报表成映射关系
- 所有写的报表的模板需要写在标签web.html_container下,而且,t-call是固定的(调用external_layout 会在报表上添加头部和底部。)
- PDF内容体是 <div class="page">内部的内容, 因为这是一个QWeb模板,你可以访问由模板接收的docs对象的所有字段。
- 有一些可在报表中访问的具体变量,主要有:
①docs针对当前报表的记录
②doc_ids针对 docs记录的id列表
③doc_model针对docs 记录的模型
④time对Python标准库 time的引用
⑤user打印报表的用户的res.user 记录
⑥res_company当前 user的公司的记录- 报表中定义页脚,div中class="footer" <span class="page"/>表示的是一条数据所占的页数的当前页 <span class="topage"/>表示的一条数据所占的页数的总页数
<!--模板id:module_name.自定义报表模板名称,去掉module_name-->
<template id="material_storage_pdf2">
<t t-call="web.html_container">
<!--循环倒入记录,这里没有定义model文件就可以直接使用记录的所有数据,如果定义了模型就需要自己写返回的数据-->
<t t-foreach="docs" t-as="record">
<!-- web.external_layout odoo自带的模板,可以在设置选择使用模板;web.internal_layout 内部模板,基本上没什么样式-->
<t t-call="web.internal_layout">
<div class="page">
<table>
<tbody>
<tr>
<td style="border:1px solid black;vertical-align: middle;text-align: center;" colspan="4">
物料标识卡
</td>
</tr>
<tr>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
申购序号
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
<t t-esc="record.source_id.name"/>
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
质检人员
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
<t t-esc="record.maker_id .name"/>
</td>
</tr>
<tr>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
物料名称
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;" colspan="3">
<t t-esc="record.product_id.name"/>
<t t-esc="record.attribute"/>
</td>
</tr>
<tr>
<td style="border:1px solid black;vertical-align: middle;text-align: center;" >
入库数量
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
<t t-esc="record.storage_quantity"/>
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
入库日期
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
<t t-esc="record.storage_date"/>
</td>
</tr>
<tr>
<td style="border:1px solid black;vertical-align: middle;text-align: center;">
备注
</td>
<td style="border:1px solid black;vertical-align: middle;text-align: center;" colspan="3">
<t t-esc="record.note"/>
</td>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</t>
</template>
4. 还可以定义pdf报表的纸张类型(默认是A4)
纸张格式是report.paperformat 记录并可包含如下属性:
- id: id的取值和报表模板中的template的id一样,也就是相等的,相当于做的映射关联
- name: 仅用于在某种列表中查看报表的助记内容/描述
- description格式的简短描述
- format是预定义格式(A0到A9, B0到 B10, 法律文书, 信件, 公报,…) 或 自定义;默认为 A4。你果定义页面大小时不能使用非自定义格式。
- dpi输出DPI;默认为90
- margin_top, margin_bottom, margin_left, margin_right单位为mm的边框大小page_height, page_width 单位为mm的页面大小
- orientation横向或纵向,
- header_line显示头部线的布尔值
- header_spacing 单位为mm的头部间距
<record id="material_storage_pdf2_paper" model="report.paperformat">
<field name="name">物料卡纸张定义</field>
<field name="default" eval="True"/>
<!--定义纸张类型-->
<field name="format">A4</field>
<!--横向打印-->
<field name="orientation">Landscape</field>
<!--纵向打印-->
<!-- <field name="orientation">Portrait</field>-->
<!--边框间距,单位mm。以下同样-->
<field name="margin_top">10</field>
<field name="margin_right">10</field>
<field name="margin_bottom">20</field>
<field name="margin_left">10</field>
<!--自定义页面大小-->
<!-- <field name="page_height">297</field>-->
<!-- <field name="page_width">210</field>-->
<!--显示头部线(页眉线)的布尔值-->
<field name="header_line" eval="False"/>
<!--显示头部的间距(页眉到顶部的距离)-->
<field name="header_spacing">0</field>
<field name="dpi">90</field>
</record>
以上内容均定义在material_storage_pdf.xml文件中
3. 在manifest文件中引入material_storage_pdf.xml文件
# data: 加载XML文件。有先后顺序,如果有调用需要将被调用的放在前面
'data': [
'security/quality_inspection_security.xml',
'security/ir.model.access.csv',
'wizard/material_storage_wizard_view.xml',
'views/inspection_manual_view.xml',
'views/incoming_inspection_view.xml',
'report/quality_inspection_report_pdf.xml',
'report/material_storage_report_pdf.xml',
'report/material_storage_report_pdf2.xml',
4. 定义报表模型
(自己测试发现可以不用定义,直接写xml文件也能实现,定义了操作起数据反而更麻烦,全部需要自己写,但这里还是写出定义方法)
@api.model
def _get_report_values(self, docids, data=None):
pass这个方法是必须继承的,也就是必须要写的 ,return的值是给template里面来用的,可以自己写,该方法里面一般写的就是报表的处理逻辑。
该方法中的参数:
① docids:是你打印时候选的几个数据,这块就是几个数据的id,组成的列表
②data是报表的类型,后台打印出这两个参数的值为
from odoo import models, api, fields
class QualityInspectionReport(models.AbstractModel):
# _name内容由三部分构成,report. + 关联模块名. + xml文件模板id组成(quality_inspection_report_pdf.xml的template id="quality_inspection_pdf")
_name = 'report.quality_inspection.quality_inspection_pdf'
_description = '质检报告pdf'
@api.model
def _get_report_values(self, docids, data=None):
report_ids = self.env['purchase.record'].browse(docids)
docs = []
for record in report_ids:
record_dic = {
'name': record.name,
}
docs.append(record_dic)
docargs = {
'doc_ids': docids,
'doc_model': 'purchase.record',
'docs': docs,
}
return docargs
定义完记得在init文件中导入 模型
5. 效果
odoo14 wkhtmltopdf 安装参考:odoo14 pdf报表 wkhtmltopdf 安装
若有不足之处,欢迎一起讨论。