如何在Frappe框架中实现客户提交订单时自动生成Bill单据
分步实现订单提交后生成Bill文档的方案
一、先确认/创建Bill Doctype
如果还没定义Bill这个文档类型,先在Frappe后台完成:
- 进入Frappe后台 → 搜索Doctype → 点击「新建」
- 填写Doctype名称为
Bill,设置命名规则(比如BILL-.YYYY.-.#####),按需勾选「提交」选项(如果需要审核流程) - 添加和订单关联的字段:
- 基础字段:
order_id(链接类型,关联你的Order Doctype)、customer_name(数据类型)、total_amount(货币类型) - 子表格字段:
items(关联新建的Bill ItemDoctype,包含item_name、quantity、price等字段)
- 基础字段:
- 保存并同步Doctype到数据库
二、编写服务器端生成Bill的Python函数
服务器端逻辑负责创建并保存Bill文档,避免前端直接操作数据库:
- 在你的App目录下(比如
your_app/your_app)新建文件bill_generator.py - 写入以下代码:
import frappe @frappe.whitelist() def create_bill_from_order(order_name): # 获取目标订单的完整数据 order = frappe.get_doc("Order", order_name) # 初始化新的Bill文档 bill = frappe.new_doc("Bill") bill.order_id = order.name bill.customer_name = order.customer_name bill.total_amount = order.total_amount # 复制订单的商品列表到Bill的子表格 for item in order.items: bill.append("items", { "item_name": item.item_name, "quantity": item.quantity, "price": item.price }) # 保存Bill到数据库(如果需要直接提交账单,替换为bill.submit()) bill.save(ignore_permissions=True) frappe.db.commit() return {"status": "success", "bill_name": bill.name}
- 说明:
@frappe.whitelist()标记该函数允许前端调用;frappe.get_doc用于读取订单数据;frappe.new_doc创建新的Bill实例;append处理子表格数据;save完成数据库写入
三、前端绑定提交按钮的触发逻辑
假设订单页面是Frappe标准Doctype表单,添加客户端脚本绑定提交事件:
- 打开你的Order Doctype编辑页 → 切换到「客户端脚本」标签
- 写入以下代码:
frappe.ui.form.on('Order', { // 监听订单提交成功后的事件 after_submit: function(frm) { // 调用后端生成Bill的函数 frappe.call({ method: 'your_app.your_app.bill_generator.create_bill_from_order', args: { order_name: frm.doc.name }, callback: function(r) { if(r.message.status === 'success') { frappe.msgprint(`已成功生成账单:${r.message.bill_name}`); } else { frappe.msgprint('生成账单失败,请重试'); } } }); } });
- 说明:
after_submit是订单提交成功后触发的钩子;frappe.call是Frappe前端调用后端函数的标准方法;method参数替换为你的App实际路径;args传递当前订单的ID;callback处理后端返回结果
四、测试验证
- 打开一个订单表单,填写信息后点击「提交」
- 提交成功后会弹出提示,显示生成的Bill名称
- 进入Frappe后台搜索
Bill,检查是否生成了对应文档,确认订单详情是否正确同步
核心概念说明
- Doctype:Frappe的核心概念,对应数据库表的定义,每个Doctype包含字段、权限、业务逻辑等配置
- 客户端脚本:Frappe表单页面的JS逻辑,用于处理交互、调用后端接口
- 服务器端函数:用Python编写的业务逻辑层,通过
@frappe.whitelist()暴露给前端调用,负责数据库操作和复杂业务处理 - Frappe ORM:
frappe.get_doc、frappe.new_doc等封装方法,无需编写原生SQL即可操作数据库
内容的提问来源于stack exchange,提问作者SM9
相关产品推荐
相关产品推荐

