先说结论
Odoo CRM 的自动分配,不是“来了 10 条线索,3 个人一人分 3 条,最后 1 条随便给谁”。
源码真正做的是两层分配:
- 先把未分配 lead 分到不同 sales team
- 再把 team 里的 lead 分到具体成员
而且每一层都不是平均主义,而是会同时考虑:
- team 的总容量
assignment_max - 成员过去 24 小时和 30 天的负载
- 团队 domain
- 成员 domain
- preferred domain
- 新线索创建后的延迟窗口
- 重复线索去重
所以 Odoo 的分配逻辑,更像:
按容量、规则和优先匹配做带约束的投放
而不是“按人数均匀发牌”。
一、自动分配其实分成 team 层和 member 层
crm.team 里有两个关键动作:
_allocate_leads()_assign_and_convert_leads()
前者负责:
- 给 lead 找 team
后者负责:
- 在 team 内找 salesperson
- 并在分给 salesperson 时把 lead 转成 opportunity
这点很容易被忽视。
很多人以为自动分配只是在“给负责人”。
其实 Odoo 先问的是:
- 这条 lead 该进哪条 team pipeline?
然后才问:
- 在这个 pipeline 里,谁该接它?
这就是为什么 team 配置和成员配置都很重要。
二、team 层不是均分,而是按容量做加权分配
_allocate_leads() 的注释写得非常明白:
- 只看还没分配的 lead
- 只看未赢单、未归档的 live lead
- 默认只看最近几天创建的 lead
- 可额外设置
crm.assignment.delay - 然后按 team 的
assignment_max做加权选择
也就是说,两个 team 同时匹配一批 lead 时, Odoo 不是简单一半一半, 而更像按“可承接能力”比例去分。
如果 Team A 的月容量是 90,Team B 是 30, 那 A 理论上就应该拿到更多线索。
这比平均分更接近真实业务。
因为现实里销售团队从来不是人人等大、组组等大。
三、为什么系统有时不碰“老 lead”
_allocate_leads() 里有一个很容易漏看的参数:creation_delta_days。
默认 cron 分配时,系统只考虑最近一段时间创建的 lead,而不是把历史积压全翻出来一起洗牌。
再配合 crm.assignment.delay,意思就更清楚了:
- 新 lead 刚进来后,可以先留一点缓冲时间
- 让别的自动规则、人工校验、入口清洗先跑完
- 然后再进入 assignment 流程
这其实很实用。
因为很多公司并不希望“刚进系统 3 秒钟的 lead”立刻被派单。
比如还要先做:
- 来源清洗
- 基础去重
- 地区识别
- SLA 预处理
所以 Odoo 的分配逻辑里,天然有一个“别太急”的设计。
四、team domain 先决定“这类 lead 归哪组”
每个 team 可以有 assignment_domain。
它的意思不是“组里谁来接”, 而是:
这个 team 有资格接什么 lead。
比如你可以让某个 team 只接:
- 高优先级 lead
- 某个国家的线索
- 某类来源的线索
- 某些产品线机会
源码甚至在约束里直接校验这个 domain 格式对不对。
这说明 Odoo 并不把它当成临时玩法, 而是把它当成正式分配规则的一部分。
如果多个 team 的 domain 有重叠,系统会按容量加权去分。
如果某个 team 根本匹配不到 lead,它就不会被硬塞线索。
五、成员 quota 不是月配额直发,而是折算成日额度
很多人看到 assignment_max,直觉会以为:
- 这个月最多给他 30 条
源码不是这么粗暴做的。
在 crm.team.member._get_assignment_quota() 里,
系统先算:
assignment_max / 30
再四舍五入成当天 quota。
然后如果不是 force_quota=True,还要再减去:
- 过去 24 小时已经分给他的数量
lead_day_count
这就意味着:
成员配置的其实是平均月承载能力,系统真正执行的是按天限流。
这设计非常合理。
因为自动分配 cron 可能一天跑多次, 如果不做“日剩余额度”,系统会在同一天里不断给同一个人塞线索。
六、为什么有的人总能先拿到更合适的 lead
这和 assignment_domain_preferred 有关。
_assign_and_convert_leads() 在 team 内分配时,明显做了两轮:
第一轮:先分 preferred leads
系统先看成员有没有 assignment_domain_preferred。
如果有,就优先把命中的 lead 先分给这些成员。
而且排序时还会优先考虑高概率 lead。
第二轮:再用普通 domain 补满
剩下没分掉的,再按普通 assignment_domain 去匹配,继续 round robin。
这意味着 preferred domain 的语义不是“只允许接某类线索”, 而更像:
当这类线索出现时,优先给我。
这是比单纯 domain 更细的一层控制。
比如:
- 某个销售擅长制造行业,优先接制造线索
- 某个销售专做高概率大单,优先吃高价值机会
- 某个销售会法语,优先接法语区来单
七、自动分配顺手还会做去重
在 team 层 _allocate_leads() 里,还有一件非常重要的事:
- 分配过程中会调用 deduplicate / merge
也就是说,Odoo 不想把重复 lead 派给不同 team 或不同销售。
这是一个非常“运营导向”的设计。
因为在真实 CRM 里,最可怕的不是少分一条, 而是同一个客户被两个人同时跟。
所以源码选择了一个更稳的顺序:
- 先找候选 lead
- 发现明显重复就先 merge
- 再把结果分下去
这就是为什么 Odoo 的 lead assignment,实际上也是 pipeline hygiene 的一部分。
八、为什么手动分配和 cron 分配结果还会不同
action_assign_leads() 和 _cron_assign_leads() 的差别之一在于:
- 手动分配会强制
force_quota=True - 并且
creation_delta_days=0
翻成人话:
- 手动点“Assign Leads”时,系统更像是在做一次“强制清仓式分配”
- 自动 cron 更像“按日节奏温和分发”
这就解释了一个常见现象:
- cron 没分那么多
- 经理手动点一下却突然分出一批
不是系统不一致, 而是本来就是两种策略。
九、实战里最容易踩的 5 个坑
1. 以为自动分配就该平均
平均不等于合理。Odoo 追求的是容量匹配,不是数学平均。
2. team domain 和 member domain 混着用
team domain 决定先归哪组,member domain 决定组里谁接。两层含义不同。
3. 不理解 preferred domain
它不是普通过滤,而是“优先权”设计。
4. 忽略 creation delay
有些入口需要先清洗再派单,太快反而会放大脏数据。
5. 只盯 user_id,不盯 dedup
重复 lead 不先控住,分配做得再漂亮,pipeline 一样会脏。
十、一句话记忆法
Odoo CRM 自动分配不是平均发牌,而是先按 team 容量做分桶,再按成员 quota、domain 和优先规则做二次分配。
理解这一句,很多“为什么系统没平均分”“为什么这个销售总先接到某类 lead”的疑问就通了。
DISCUSSION
评论区