先说结论
Odoo 里的 Activity “下一步”并不是一个单一功能,而是两套机制:
- suggest:完成当前活动后,系统给你推荐下一步类型,是否创建由人决定
- trigger:完成当前活动后,系统直接自动创建下一条活动
这两个机制都挂在 mail.activity.type 上,但它们在源码里被明确设计成互斥。
所以如果你把它们理解成“一个是推荐列表,一个是推荐列表里的默认值”,就会把系统看浅。
官方真正表达的是:
Odoo 可以把 activity 配成“人为接力”,也可以配成“自动接力”,但不能同时把同一个类型两种逻辑都开满。
第一层:为什么 activity type 才是流程规则,而不是 activity 本身
很多人盯着 mail.activity 看,觉得 activity 才是核心。
但如果顺着源码看,你会发现真正决定流程感的,是 mail.activity.type。
这个模型上最关键的几个字段是:
chaining_typetriggered_next_type_idsuggested_next_type_idsdelay_countdelay_unitdelay_from
它们共同回答的是:
- 完成后有没有下一步
- 下一步是系统自动建,还是让用户手选
- 下一步的截止日期从哪一天开始算
也就是说,mail.activity 更像一次具体执行,mail.activity.type 才像流程模板。
第二层:为什么 suggest 和 trigger 被设计成互斥
mail_activity_type.py 里有两个成对的计算/逆向方法:
_compute_suggested_next_type_ids()/_inverse_suggested_next_type_ids()_compute_triggered_next_type_id()/_inverse_triggered_next_type_id()
官方逻辑很直接:
- 如果
chaining_type == 'trigger',就把suggested_next_type_ids清空 - 如果
chaining_type == 'suggest',就把triggered_next_type_id清空
这说明系统并不希望一个 activity type 既“自动长下一条”,又“让人挑多个推荐”。
原因很现实。
如果两套都开:
- 用户会看到推荐项
- 系统又自动建一条
- 最终流程会出现重复接力、责任混乱、截止日冲突
所以 Odoo 在模型层先把规则收紧了。
这是一种很典型的产品设计思路:
与其允许你配出歧义流程,不如直接限制成两种清晰模式。
第三层:完成 activity 时,系统到底在哪一步决定“下一条怎么来”
关键在 mail.activity 的完成链路。
很多人只看到界面上的 Mark Done,但源码里真正重要的是:
action_feedback()action_feedback_schedule_next()_action_done()
其中 _action_done() 最值得看。
它在遍历活动时,会先检查:
- 当前 activity 的
chaining_type是不是trigger
如果是,系统会:
- 带上
activity_previous_deadline=activity.date_deadline上下文 - 调
_prepare_next_activity_values() - 把结果收集进
next_activities_values - 最后统一
create()出新的mail.activity
也就是说,自动接力不是界面层行为,而是完成动作里的业务逻辑。
这点非常关键,因为它解释了两个现象:
- 哪怕不是从某个特定前端按钮完成,只要走到这条完成链,trigger 仍然会生效
- 下一条 activity 的创建时机,和“当前活动被标记完成”是同一个事务语义里的事情
第四层:suggest 模式到底在做什么
如果是 suggest,系统不会在 _action_done() 里直接长下一条。
它做的是另一件事:把“前一条活动类型”传给后续界面逻辑。
在 mail.activity 上:
previous_activity_type_id记录前一步是什么has_recommended_activities会根据前一步的suggested_next_type_ids算出来_onchange_previous_activity_type_id()会在有 trigger 时自动切默认类型_onchange_recommended_activity_type_id()则允许用户点选推荐项后切换activity_type_id
换句话说:
- trigger 是系统替你生成下一步
- suggest 是系统替你缩小选择范围
它不是“没做事”,而是在把经验路径提前塞给用户。
这很适合 CRM、项目跟进、审批回访这类流程:
- 你不想完全自动化
- 但你又不想让执行人每次都从全部活动类型里盲选
第五层:为什么截止日期不是简单“今天加几天”
mail.activity.type._get_date_deadline() 还藏着一个容易被低估的点:
delay_from == 'current_date':从当前日期往后推delay_from == 'previous_activity'且上下文有activity_previous_deadline:从上一条活动截止日期往后推
这两种算法,决定的是流程节奏的参考基准。
区别非常大。
如果按 current_date:
- 你今天才补做完上一条
- 下一条从今天重新起算
- 整条流程会整体向后漂移
如果按 previous_activity:
- 下一条仍然按原计划节奏推
- 你晚做上一条,并不会自动把整个流程拖长
这就是为什么有些 activity 流程更像“建议跟进”,有些更像“固定节奏的 SLA”。
第六层:为什么删除 activity type 时,Odoo 还要把旧活动改成 Todo
mail.activity.type.unlink() 里有一段很有意思的处理:
- 如果删除某个 activity type,系统会先把现存活动改挂到
mail.mail_activity_data_todo - 然后再删类型本身
这说明官方很在意历史活动不能因为配置变化而失去语义落点。
同样地,一些核心类型还不允许删,比如 To-Do、Call、Meeting 这些基础类型。
这背后表达的思想很清楚:
Activity type 不是随手写的标签,它是流程配置的一部分,删改要非常保守。
实战里怎么用 suggest,怎么用 trigger
更适合 suggest 的场景
- 销售跟进:打完电话后,可能发报价,也可能约会议
- 项目协作:处理完某一步后,下一个动作要由负责人判断
- 审批追踪:系统给出推荐,但不替你决定
更适合 trigger 的场景
- 合同到期前固定提醒
- 某个文件上传后必须补一个复核动作
- 某项交付完成后一定要长出回访或质检动作
一句话:
- 存在业务分歧时,用 suggest
- 下一步几乎确定时,用 trigger
最容易踩的 4 个坑
1)以为 suggest 会自动建下一条
不会。
它主要是推荐,不是自动执行。
2)以为 trigger 只是前端默认值
不是。
trigger 是完成动作里的真实业务逻辑,走 _action_done() 时会创建新的 activity。
3)没搞懂 delay_from
如果你的流程节奏总是“越跟越晚”,先看是不是把本来该按 previous_activity 的规则配成了 current_date。
4)把 activity type 当成无关紧要的字典
不是。
它是流程编排器。删、改、归档,都会影响现有流程和用户体验。
排查“为什么没自动长下一条”的顺序
推荐按这个顺序看:
- 当前 activity type 的
chaining_type是不是trigger triggered_next_type_id是否真的配置了- 完成动作是否走了
action_feedback()/_action_done()主链 - 新 activity 的 deadline 计算是否受
delay_from影响 - 有没有把“推荐”误当成“自动生成”
这样排查,通常比盯着界面按钮更快。
最后一句
Odoo Activity 真正有价值的地方,不是“能记待办”,而是它允许你把待办配置成人工判断型接力或自动衔接型接力。
所以你要理解的不是“下一步按钮在哪里”,而是:
当前这个 activity type,到底是在给人建议,还是在替流程自动接棒。
一旦把 suggest 和 trigger 分清,很多 activity 配置会立刻清爽很多。
DISCUSSION
评论区