先说结论
Odoo CRM 里所谓“商机发霉”“pipeline 发臭”,不是一句比喻而已。
源码真的有一套机制,在判断:
- 这条机会是不是太久没推进
- 它现在的停滞,是否发生在一个应该继续推进的阶段
- 它是不是仍然属于活跃 pipeline,而不是已赢单、已丢单或普通 lead
这套机制的核心,不是看你有没有改备注, 而是看:
stage_iddate_last_stage_updaterotting_threshold_dayswon_statustype
所以 Odoo 对“pipeline hygiene”的理解非常明确:
真正需要警惕的,不是记录存在很久,而是它作为活跃 opportunity,在某个阶段停太久。
一、Rotting 不是“创建很久”,而是“阶段卡太久”
很多团队一说 pipeline 老化,第一反应是:
- 这条商机已经创建 40 天了
但 Odoo CRM 的思路不是按 create_date 粗暴判断。
源码更关注的是:
date_last_stage_update
也就是说,它关心的是:
你在当前阶段待了多久。
这就比“创建多久”合理很多。
因为现实里完全可能出现两种记录:
- A:创建 60 天,但最近还在持续推进
- B:创建 7 天,但已经 7 天没人动,且卡在一个本该快速推进的阶段
真正更脏的,往往是 B,不是 A。
二、Rotting threshold 是 stage 级配置,不是全局统一时钟
crm.stage 里有个字段:
rotting_threshold_days
这说明 Odoo 不认为所有阶段都应该用同一个超时规则。
比如:
- “初步接触”卡 3 天,可能就该报警
- “法务谈判”卡 10 天,可能还算正常
- “客户内部预算审批”卡 15 天,也未必异常
所以 rotting 的阈值是 每个阶段自己定义 的。
这非常符合真实销售流程。
因为不同阶段本来就有不同节奏, 如果全局统一按 7 天来判,误报会很多。
三、系统不是对所有 CRM 记录都做 rotting
_get_rotting_domain() 里很关键的条件是:
won_status = pendingtype = opportunity
这意味着:
- 不是所有
crm.lead都参与 rotting 判断 - 普通 lead 不算
- 已 won 的不算
- 已 lost 的不算
这个边界很重要。
因为 rotting 的目标不是“找所有旧记录”, 而是:
找那些本该还在推进、却没推进的活跃商机。
如果把 lead 也混进去,噪音会很大。 如果把 won/lost 也混进去,那就更没意义了。
四、为什么改备注、改名称不一定能让商机“变新鲜”
从测试 test_leads_rotting 能很清楚看出来:
- 编辑名称,不会让 rotting 状态消失
- 改 stage,才会重置 rotting 计时
这背后的理念其实很直白:
- 普通编辑不等于推进漏斗
- 真正推进,是阶段变化
这点很值得产品设计和实施人员记住。
很多团队会下意识想:
- 销售改了点内容,说明他有在跟进
但 Odoo 源码更保守。
它认为:
如果业务没有跨阶段推进,那就不能轻易把“卡住”的事实抹掉。
这个设计很像给 pipeline 做防注水。
五、为什么换到另一个 stage 后,rotting 会重新计算
测试里还能看到另一件事:
- 一条商机在老阶段已经 rotten
- 一旦切到新阶段,rotting 可以马上消失
- 之后按新阶段的 threshold 重新计时
这很合理。
因为 rotting 的语义不是“这条记录曾经老过”, 而是:
- 它在当前阶段有没有待太久
如果你从“Qualification”推进到“Proposal”, 那原来的停滞不应该原封不动地带到新阶段。
否则所有历史慢单,后面永远都带着 rotting 状态,也不符合业务直觉。
六、threshold 改了,历史 rotting 状态也可能跟着变
crm.stage 的 rotting_threshold_days 不是一次性计算后固化结果。
测试里很明确:
- 把 threshold 从 5 改到 50,原本 rotten 的机会可能立刻不 rotten
- 再改回去,又会恢复 rotten
- 改成 0,则直接关闭这个阶段的 rotting 检测
这说明 Odoo 把 rotting 看成一种 动态业务判断,而不是永久标记。
这对实施很有价值。
因为你可以随着团队成熟度调整节奏,而不必担心旧数据永远背着旧阈值跑。
七、Pipeline hygiene 为什么不该只靠列表筛选
很多团队做漏斗清洁,常见动作只有:
- 筛出 30 天没更新的商机
- 然后人工挨个清
这种做法最大的问题是:
- 不分阶段差异
- 不分 lead/opportunity
- 不分 pending/won/lost
- 容易把“正常慢单”和“真正卡死”混在一起
Odoo 的 rotting 机制其实给了一个更靠谱的思路:
- 只看 pending opportunity
- 用 stage 自己的 threshold
- 用最后阶段更新时间,而不是任意修改时间
这比简单按 write_date 或 create_date 筛选要干净很多。
八、fold 和 rotting 不是一回事
有些人会把 folded stage 理解成:
- 这个阶段不重要
- 或者放进去就算结束了
其实 fold 主要是 kanban 展示语义,
不等于 rotting 语义。
而 rotting 更偏:
- 这个阶段是不是还应持续推进
- 如果应推进,却迟迟没推进,就该高亮出来
所以你不能用“把 stage 折叠起来”代替 pipeline hygiene。
一个流程是否健康,最终还得回到:
- 当前阶段是什么
- 当前阶段允许停多久
- 最近一次阶段推进是什么时候
九、实战里最容易踩的 4 个坑
1. 用创建时间判断老化
创建久不等于卡住,阶段停滞才更关键。
2. 把备注编辑当作推进证据
Odoo 并不这么认,源码更看重 stage movement。
3. 所有阶段用同一个超时标准
这样会把节奏不同的销售动作全部混平。
4. 把 lead、won、lost 一起拉进老化清理
这样筛出来的是旧记录清单,不是 pipeline hygiene 清单。
十、一句话记忆法
Odoo CRM 的 rotting 不是在判断“记录老不老”,而是在判断“活跃 opportunity 在当前阶段是不是卡太久”。
理解这一句,你就会明白为什么 rotting threshold、date_last_stage_update 和 stage 设计,才是真正的漏斗卫生工具。
DISCUSSION
评论区