Frappe文件导出
Frappe文件导出
单据导出到Excel模板,一定程度上可取代标准打印功能
License
agpl-3.0
使用方法
先决条件
进入 bench 工作台目录;
1.新安装
1.1、获取对应版本APP
bench get-app https://gitee.com/zhuxing5656/frappe-file-export.git
1.2、安装APP(有多个站点且未设默认站点的请加--site参数)
bench install-app zelin_export_excel_template
升级(之前安装过未拆分前版本的请谨慎更新)
2.1、bench update 命令
bench update --apps zelin_export_excel_template --pull --reset
3、安装需要的python包
pip3 install reportlab python-docx fpdf2
建议先启用虚拟环境再安装
cd env/bin
source activate
再执行 pip3 install reportlab python-docx fpdf2
单据Excel模板导出功能
概述
类似打印格式,可为每个单据定义带字段变量与jinja表达式的excel模板,在单据表单界面导出当前单据内容到excel模板。
场景1:基于销售出库单一键导出excel版装箱单,报关单,合同,形式发票与申报要素,交给货代去录入海关系统作报关申请。无此功能时,需手工逐单逐字段复制粘贴到对应excel模板,耗时耗力,容易错漏。
场景2:发给供应商采购订单或给客户销售出货单,除给PDF或纸单外,可以给excel电子版,方便对方批量导入或接口程序自动录入系统。
场景3:从报价单提取指定字段的物料明细到excel,用于向供应商询价
系统明细表可导出,但包括了全部字段以及不需要的表头,导出字段不可定制
可自定义报表选择需导出的字段,使用过滤条件筛选,再点导出,还需要将导出数据复制粘贴到自己的excel模板,操作繁琐
实现原理
上传为目标单据类型定义的带字段变量与Jinja表达式的Excel模板到服务器,单据表单界面新增导出excel菜单按钮,代码加载excel模板,逐个excel单元格解析文本串中包含字段与jinja表达式变量,替换变量值为当前单据字段值或Jinja表达式结果,下载成excel文件。
具体操作
一、维护Excel模板
1.变量处理
(1)当前单据变量为doc
(2)变量用双花括号{{}}表示
①使用{{doc.字段名}}引用普通字段(非明细表), 如{{doc.customer}} 当前单据客户字段
②支持jinja表达式变量:即可返回文本的一条语句python脚本
用途 函数 范例
显示链接的关联字段(excel vlookup) frappe.db.get_value {{frappe.db.get_value("Address",doc.shipping_address ,"country")}}
根据地址编号返回地址表中的国家
翻译为打印语言 () {{(row.item_name)}} 翻译明细行的物料名称
金额大写 doc.money_in_words {{doc.money_in_words(doc.total)}}
单据制单人 doc.get_owner_username {{doc.get_owner_username()}}
单据审批人 doc.get_submit_username {{doc.get_submit_username()}}
明细表数量、金额字段汇总小计 frappe.db.get_value {{frappe.db.get_value('Delivery Note Item', {'parent':doc.name},'sum(total_weight)')}}
基于明细表总重量计算整个单据总重量
(3)同一单元格式支持正常文本与变量混合,如客户名称: {{doc.customer_name}},
(4)一个文本串中可包含多个变量
2.明细表处理
(1)需在输出明细行内容的第1列(A列)填写如下格式的批注:row=doc.items, 其中row=是固定内容,代码通过这个固定文本为明细行变量赋值(绑定子表字段),doc.items表示该明细行对应的子表字段名
(2)当前明细行对象变量为row, 如{{row.item_code}}表示明细行的物料编号字段
(3)模板定义时明细行输出内容只需保留一行,代码会根据单据实际明细行自动新增行,如单据有5个明细行,最终输出结果会在原模板一行明细定义基础上再新增4行,底下所有行自动下移
3.特殊处理
(1)引用不存在字段,excel文件输出原变量字符串,系统错误日志有详细出错信息
(2)空值字段,返回空字符串
(3)系统内地址信息是通过地址模板定义带换行符的多行文本,Excel模板中相关单元格格式需设为自动换行(可同时合并上下单元格)
(4)图片字段,如订单明细中的image字段,可以单元格写字段变量{{row.image}},代码会将以.png,.jpg,.img结尾的图片加载到绑定的单元格,需注意上传的图片尺寸。
二、维护单据类型Excel导出模板
单据类型
模板名称
模板文件:上传已定义的Excel模板文件
多语言:如果勾选导出Excel时用户需选择语言,同时Excel模板中需调用_()函数翻译标签,类似这样{{_('Item Code')}}
导出文件名: python表达式,默认的导出文件名为{{template_name}}_{{doc.name}}.{{path[-4:]}},模板名_单据名.文件名后缀,可使用doc,template_name,path(含后缀的文件名)
三、单据导出excel文件
本app也支持word文件模板
25/01/22 feat:(PDF Export)
支持 Excel (.xlsx) 转 PDF,支持 Word (.docx) 转 PDF,保持原文件格式和样式
一、服务器安装
sudo apt-get update
sudo apt-get install -y libreoffice-writer libreoffice-calc
二、代码修改总结
主要修改 (api.py):
● 添加了新的 export_pdf 函数,实现PDF导出功能
● 使用 LibreOffice 的 soffice 命令进行文件转换
● 使用用户主目录下的临时文件夹进行文件处理
关键代码流程:
# 1. 创建临时目录
temp_dir = os.path.join(os.path.expanduser('~'), '.temp_pdf_export')
os.makedirs(temp_dir, exist_ok=True)
# 2. 生成源文件(支持Excel和Word)
if path.endswith('.docx'):
# Word文档处理
temp_file = process_docxtpl(path, doc)
source_file = os.path.join(temp_dir, 'temp.docx')
else:
# Excel文件处理
temp_file = openpyxl.load_workbook(filename=path)
for ws in temp_file.worksheets:
process_worksheet(ws, doc, language, bench_path)
source_file = os.path.join(temp_dir, 'temp.xlsx')
# 3. 使用LibreOffice转换为PDF
process = subprocess.run(
['soffice', '--headless', '--convert-to', 'pdf', '--outdir', temp_dir, source_file],
capture_output=True,
text=True,
timeout=30
)
# 4. 读取并返回PDF文件
with open(pdf_file, 'rb') as f:
pdf_content = f.read()
错误处理:
● 添加了详细的错误日志记录
● 实现了临时文件的自动清理
● 添加了文件存在性检查
前端集成:
// 添加PDF导出按钮,与Excel导出按钮类似
frm.add_custom_button(__(d.template_name), function() {
if (d.is_multi_language) {
// 多语言处理
var dialog = new frappe.ui.Dialog({
title: __('Select Language'),
fields: [
{
fieldtype: "Link",
options: "Language",
default: frappe.boot.lang,
label: __("Language"),
reqd: 1,
fieldname: "language"
}
],
primary_action: function(values) {
open_url_post(pdf_api_url, {
doc: frm.doc,
template_file: d.template_file,
template_name: d.template_name,
export_file_name: d.export_file_name || "",
language: values.language
});
dialog.hide();
},
primary_action_label: __('Export PDF')
});
dialog.show();
} else {
// 直接导出PDF
open_url_post(pdf_api_url, {
doc: frm.doc,
template_file: d.template_file,
export_file_name: d.export_file_name || "",
template_name: d.template_name,
});
}
}, __("Export PDF"));
在每个支持的文档类型中添加了"Export PDF"按钮 、 支持多语言选择,保持与Excel导出相同的用户体验