先说结论
crm.stage.is_won 在 Odoo CRM 里不是“前台显示一个赢单徽标”这么简单。
它背后带的是一整套语义:
- 该阶段上的机会应该被视为赢单;
- 概率应当对齐到 100;
- 如果后来取消 Won 属性,就要重新回到自动概率体系。
所以源码在 crm.stage.write() 里直接做了批量处理:
- 勾上
is_won:该阶段上的商机统一写成probability=100、automated_probability=100; - 取消
is_won:该阶段上的商机调用_compute_probabilities()重算。
这就是为什么它会影响一大片记录。
一、为什么源码先弹警告
crm.stage 的 _onchange_is_won() 明着提醒:
改 Won 属性,可能诱发大量操作,因为该阶段商机的概率会重算。
这不是 UI 夸张提示,而是模型层真实副作用。
如果一个阶段本来挂着很多机会,你一勾或一取消,受影响的不是阶段配置本身,而是全部在该阶段上的商机数据。
二、Won 语义在 Odoo 里是“阶段 + 概率”联动,不是二选一
很多团队习惯把“赢单”理解成两个独立开关:
- 阶段走到成交;
- 概率自己手工填 100%。
但 Odoo 更强约束:
stage_id.is_won=Trueprobability=100
两者应尽量一致。
在 _compute_won_status() 里,只有当:
probability == 100- 且
stage_id.is_won
系统才判定 won_status='won'。
也就是说,只改其一,语义并不完整。
三、为什么取消 Won 后会让人觉得“手工概率被吃了”
crm.stage.write() 的注释已经说透:
- 如果某阶段先被设为 won,系统会把该阶段商机概率推到 100;
- 如果你很快又把这个阶段改回非 won,系统会重新算自动概率;
- 过程中手工概率可能丢失。
这件事的本质是:
系统无法知道你之前那个人工概率,到底是业务判断,还是被 Won 阶段强行推出来的结果。
所以它只能回到自动概率逻辑,而不是替你恢复历史手工值。
四、为什么这类变更要当“数据迁移”而不是“配置微调”
很多实施项目在上线后会不断改阶段:
- 新增一个“合同盖章中”;
- 把“成交”改名;
- 把某个历史阶段也勾成 Won。
如果只是改名字,风险不大。
但只要碰 is_won,就已经不是简单配置,而是在改数据语义。
因为它会改变:
- 商机是否算赢单;
- 概率是否被改写;
- 关闭时间与相关统计是否被触发;
- 预测报表口径是否变化。
五、最容易踩的误区
1. 以为 Won 只是看板颜色
错,它会写记录。
2. 以为取消 Won 后会恢复之前的手工概率
错,源码只承诺重算,不承诺“历史回放”。
3. 以为只要概率 100 就等于赢单
不够,还要看阶段是否是 Won 阶段。
4. 以为改阶段配置不会影响历史数据
只要碰 is_won,历史和现存记录都可能被波及。
六、实务上的正确操作顺序
如果你必须改 Won 相关配置,建议顺序是:
- 先确认哪些阶段应该承载赢单语义;
- 盘点这些阶段当前挂着多少机会;
- 评估概率、关闭时间、报表是否会一起受影响;
- 尽量在低峰时段改;
- 改完抽查几条历史商机,看
stage/probability/won_status/date_closed是否一致。
一句话记忆
在 Odoo CRM 里,把阶段设成 Won 不是改皮肤,而是在批量重定义这批商机的赢单语义和概率状态。
DISCUSSION
评论区