先说结论
在 Odoo CRM 里,Sales Team 绝对不只是一个“方便筛选的标签”。
它至少同时在管 4 件事:
- 这条线索默认归哪条销售管道
- 这条记录能落到哪些阶段里
- 团队邮箱入口新进来的记录默认是什么类型
- 用户切换负责人后,系统该把记录自动拉回哪个团队
所以如果你把 team_id 只理解成“部门字段”,后面很容易遇到这些现象:
- 为什么换了 salesperson,team 也跟着变了
- 为什么某个 stage 突然选不到了
- 为什么同一个 CRM,看起来像有几条不同 pipeline
- 为什么邮件 alias 进来的记录直接带了 team 和 type
这些都不是偶发行为,而是 Odoo 源码本来就把 team 当成 pipeline 作用域的核心锚点。
一、Sales Team 在源码里首先就是 pipeline 的入口
看 crm.team 模型时,几个字段连在一起就很说明问题:
use_leadsuse_opportunitiesalias_idassignment_domainlead_properties_definition
这里最容易被低估的是 alias_id。
源码里明确写着:
这个邮箱地址收到新邮件后,会自动创建 lead,并分配到这个 channel / team。
也就是说,团队并不只是“已有线索归谁看”的问题, 它还是 新线索进入系统时的落点。
如果一个团队开启了 use_leads,那 alias 默认创建出来的通常就是 lead;
如果没有 lead 资格流程,而是直接做 pipeline,alias 默认就更偏 opportunity。
这就是 _alias_get_creation_values() 在做的事:
- 根据团队配置决定默认
type - 把
team_id直接写进 alias 默认值
翻成人话:
团队不是后面再归类,而是线索进门时就已经参与定向。
二、team_id 会直接限制你能用哪些 stage
crm.lead.stage_id 的定义里有一段很关键的 domain:
- 全局 stage 可以用
team_ids包含当前team_id的 stage 也可以用
也就是说,stage 不是全公司无限共享的平面列表。
它实际上分两类:
- 全局 stage:所有团队都能看见
- 团队专属 stage:只对指定
team_id可见
这件事非常重要。
因为很多实施项目会把团队理解成“销售一部 / 销售二部”, 但 Odoo 更鼓励你把团队理解成:
- 不同业务线
- 不同 pipeline
- 不同销售动作体系
例如:
- 直销团队有 Demo、报价、法务审批这些 stage
- 渠道团队可能更关心 Partner onboarding、联合推进
- 售前咨询团队可能根本不用后面那套报价阶段
如果你不做团队级 stage 作用域,所有阶段混在一起,pipeline 很快就会脏。
三、为什么换负责人后,team 也可能自动变
crm.lead._compute_team_id() 的逻辑非常值得注意。
核心意思是:
- 如果这条记录已经有 team,而且当前 user 就属于这个 team,那先保留
- 但如果 user 不属于当前 team,系统会重新按 user 去找默认 team
- 同时它还会区分当前记录是
lead还是opportunity
这说明 Odoo 的思路不是“负责人和团队彼此独立”。
而是:
负责人和团队在 CRM 里应该尽量保持语义一致。
所以你在界面里把 salesperson 改成另一个团队的人时, 系统并不是单纯换个人, 而是在问:
- 这条记录现在应该属于谁的 pipeline?
很多人第一次看到这个行为会觉得“怎么 team 自己变了”。
其实不是自己变,
而是 team_id 本来就被当成 pipeline 归属字段,而不是纯装饰字段。
四、为什么有时一改 team,stage 也会被重算
_compute_stage_id() 里还有一段典型逻辑:
如果当前 stage 不存在,或者当前 stage 属于某些团队、但新的 team_id 不在其范围里,系统就重新找一个非 folded 的可用 stage。
这意味着什么?
意味着 Odoo 在尽量避免一种脏数据:
- 记录已经切到 Team B
- 但 stage 还挂着 Team A 专属阶段
这会让 kanban、统计、看板列都开始失真。
所以源码选择了一个更稳的策略:
- 只要 stage 跟 team 作用域不再匹配
- 就重新找一个当前 team 可用的默认 open stage
这也是为什么很多人会觉得:
- 我只是换了 team,怎么 stage 也动了
答案是:
因为在 Odoo 眼里,team 和 stage 本来就是绑定的,不让它们错位比“保持用户原值”更重要。
五、kanban 上看到哪些列,也跟 team 有关
_read_group_stage_ids() 和 _stage_find() 都在处理同一个问题:
- 当前上下文下,哪些 stage 应该展示出来
- 当前记录属于哪个 team 时,默认应该找哪些 stage
尤其 _read_group_stage_ids() 很典型:
- 已经出现过的 stage 列要保留
- 全局非 folded stage 要出现
- 当前 team 可用的非 folded stage 也要出现
这不是简单的“把所有 stage 全列出来”。
它是在做一个折中:
- 看板要完整 enough
- 但又不能把不属于这条 pipeline 的阶段全混进来
所以一个团队的 kanban 视图,本质上就是:
当前 team 作用域内的可操作阶段集合。
这也解释了为什么 Odoo CRM 的多团队体验,和“一个公共看板加一个 team 筛选器”很不一样。
六、Sales Team 其实还隐含了一种业务设计边界
crm.team 上还有 lead_properties_definition、use_leads、use_opportunities 这些字段。
这说明官方不是把 team 当成纯组织架构对象, 而是当成一种 业务线配置容器。
也就是说,团队在 CRM 里往往代表:
- 一套入口
- 一套资格判断方式
- 一套阶段体系
- 一套负责人分配规则
- 一套需要采集的属性
从实施角度看,最稳的理解方式不是“team = 部门”, 而是:
team = 一条有自己规则的销售管道。
部门只是它最常见的一种映射方式,不是唯一方式。
七、实战里最容易踩的 4 个坑
1. 把 team 只当报表字段
这样会导致 stage、默认负责人、alias 入口都设计得很散。
2. 不区分全局 stage 和团队 stage
一开始图省事,后面所有团队共用一套阶段,pipeline 会越来越像大杂烩。
3. 改 salesperson 时没意识到 team 会联动
结果以为是 bug,实际是源码在维护 team-user 一致性。
4. 把一个完全不同销售流程硬塞进同一 team
如果流程本质不同,应该优先考虑拆 team,而不是继续给同一个 pipeline 加补丁。
八、一句话记忆法
记住这一句就够了:
Odoo CRM 里的 Sales Team 不是“人群标签”,而是 pipeline 的作用域对象:它决定入口、默认 team、可用 stage,以及很多后续自动行为。
理解了这句,你再看 team_id,就不会把它当成一个可有可无的 Many2one 了。
DISCUSSION
评论区