触发器决定自动化流程何时被考虑。匹配字段和条件决定某个特定文档是否符合条件。两者都在自动化流程表单上设置。
触发器类型
| 触发器类型 | 触发时机 | 所需配置 |
|---|---|---|
| 文档创建 | 插入文档时 | 文档类型 |
| 文档更新 | 保存已有文档时(插入时不触发) | 文档类型 |
| 字段值变更 | 保存时某个字段的值发生变化 | 文档类型、触发字段 |
| 文档删除 | 删除文档时 | 文档类型 |
| 文档提交 | 提交可提交的文档时 | 文档类型 |
| 文档取消 | 取消可提交的文档时 | 文档类型 |
| 基于日期 | 日期字段在今天的 N 天前或 N 天后 | 文档类型、日期字段 |
| 定时调度 | cron 表达式到期时 | Cron 表达式 |
| 自定义事件 | 应用调用 frappe.automation_engine.emit() 时 |
自定义事件名称 |
| 手动 | 有人显式启动流程时 | — |
字段值变更
将触发字段设置为要监视的字段。可选地通过以下方式缩小范围:
- 原值:仅当旧值为该值时触发。
- 新值:仅当新值为该值时触发。
任一项留空表示接受任意值。例如,触发字段为 status,新值为 Closed,则每当文档被关闭时触发,无论其之前的状态是什么。
基于日期
选择一个日期字段、一个日期偏移(天)和一个日期方向:
3天之前renewal_date:对续约日期距今三天的文档触发。1天之后due_date:对昨天变为逾期的文档触发。
基于日期的流程每小时检查一次。无论检查运行多少次,每个文档每天最多触发一次。
定时调度
输入标准的五字段Cron 表达式,例如 0 9 * * 1 表示每周一 09:00。保存后表单会显示下次运行时间。
- 不设置文档类型时,流程按调度运行一次,不涉及文档。适用于周期性任务,如每周摘要邮件或调用外部 API。
- 设置文档类型时,每次调度到期时,流程会为每个匹配其匹配字段和条件的文档各运行一次。
如果调度器宕机错过了多次触发,流程只会为最近一次补运行一次,而不是为每次错过的触发都补运行。
自定义事件
自定义事件流程在应用发出命名事件时运行,例如 crm.deal_won。在自定义事件中按应用发出的事件名称准确输入。应用如何发出和注册事件在扩展自动化中介绍。
如果设置了文档类型,流程仅对该类型文档相关的事件运行。
手动
手动流程不会自行触发。仅当应用通过 frappe.automation_engine.api.run_manually 方法启动它时才运行,例如从应用 UI 中的按钮启动。调用者需要对流程有写权限,对文档有读权限。
匹配字段
匹配字段使用与列表视图相同的筛选编辑器。每个字段规则添加一行。文档必须满足所有规则,流程才会运行。
例如,在一个线索流程中:
- 状态 =
Open - 来源已设置
- 年收入 >
1000000
没有匹配字段的流程会匹配其类型的所有文档。
高级条件
对于匹配字段无法表达的逻辑,在使用 Python 的高级表达式中编写 Python 表达式。文档可通过 doc 访问,表达式使用 Frappe 的安全求值器求值,因此可以使用 frappe.utils 辅助函数。
doc.status == "Open" or doc.priority == "High"
doc.grand_total > 50000 and doc.customer_group != "Internal"
匹配字段和表达式必须同时为真。如果表达式抛出错误,文档将被视为不匹配,错误会写入错误日志。
运行时重新验证
触发器在文档保存时匹配,但步骤稍后在后台工作进程中运行。勾选运行时重新验证可在执行前再次测试匹配字段和条件。如果文档不再匹配,该次运行将记录为已跳过。
当文档在触发流程的保存之后可能快速变化时(例如状态被设置后又还原),这很有用。
运行身份
运行身份决定步骤以谁的权限运行:
- 自动化用户(默认):自动化用户字段中的用户,除非你更改它,否则为
Administrator。 - 触发用户:其操作触发了流程的用户。
- 文档所有者:流程所针对的文档的所有者。
每个步骤仍以该用户的身份运行正常的权限检查。如果某个步骤因权限错误而失败,请检查“运行身份”用户是否能够读取触发文档并写入该步骤所更改的记录。
当流程未触发时
在安装、迁移和补丁期间,当自动化设置中勾选了禁用自动化时,以及在 site_config.json 中设置了 automation_disabled 时,自动化流程会被跳过。
必须在不触发流程的情况下保存文档的代码(例如数据导入)可以抑制流程:
from frappe.automation_engine import skip_automations
with skip_automations():
doc.save()