Frappe文件导出

Author Avatar
ZhuXing
发表:2025-01-22 13:07:00
修改:2025-01-22 13:08:43

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导出相同的用户体验

评论