CRM 深度

Odoo CRM 线索转商机为什么不是“改个 type”:convert wizard、客户匹配和负责人分配的真实顺序

很多人把 Odoo CRM 的‘转商机’理解成一个简单按钮:点一下,lead 变 opportunity。源码里真正发生的是客户匹配、重复机会判断、联系人创建/挂接,以及负责人和 team 的再分配。

CRM
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

先说结论

Odoo CRM 的“Convert to opportunity”,不是把 typelead 改成 opportunity 就结束。

源码真正做的是一条有顺序的业务链:

  1. 先判断这条 lead 该不该直接 merge
  2. 再决定客户是新建还是挂到现有 partner
  3. 必要时先处理 commercial partner / parent company
  4. 然后才执行 convert_opportunity()
  5. 最后再看要不要强制改 salesperson 和 sales team

所以“转商机”本质上不是字段切换, 而是一次 线索资格确认 + 客户归属落位 + 负责人承接 的组合动作。


一、wizard 默认就在帮你猜“该挂谁”

入口在 crm.lead2opportunity.partner

这个向导不是空白表单。default_get() 和一系列 compute 方法会先做预判:

  • 如果当前 lead 已经能匹配到 partner,action 默认就是 exist
  • 如果发现重复线索足够多,name 会默认成 merge
  • user_id 默认继承 lead 当前负责人
  • team_id 会跟着负责人重新找默认 team

这意味着用户看到的默认选项,其实已经带了 Odoo 的业务判断:

这条线索更像是“转成一个新机会”,还是“并入已有客户/已有机会体系”。

所以很多人觉得 wizard “很聪明”,不是错觉,它确实先跑了一轮源码判断。


_compute_action() 会先调用 lead._find_matching_partner()

也就是说,Odoo 在转商机前,优先想做的不是“新建客户”, 而是先问:

  • 这个邮箱是不是已经有联系人?
  • 这个线索是不是其实已经对应某个客户?

在测试里,哪怕客户名称写法不同,只要邮箱归一化后能对上,wizard 也会偏向 exist

这背后的设计很现实:

如果 CRM 入口很多——网页表单、人工录入、邮件别名、导入—— 同一个客户被重复创建,是最常见的数据污染源之一。

所以 Odoo 的默认姿势不是“多建客户”,而是 尽量复用现有客户主数据


三、merge 不是“把几条线索装进一个文件夹”

如果 wizard 判断 name='merge',走的是 _action_merge()

这里的重点有三个:

1. 先把重复机会集合起来

源码里是:

  • duplicated_lead_ids | lead_id

也就是把当前 lead 和所有判断为重复的机会放到一起处理。

2. 调 merge_opportunity() 选出一个结果记录

真正保留下来的不是“全部拼接”, 而是由合并逻辑选一个结果商机,其他记录成为被吸收方。

3. 最后把其余重复记录删掉

(to_merge - result_opportunity).sudo().unlink()

所以 merge 的本质其实是:

选一个主机会,别的记录把有价值的关联迁过去,然后清掉重复壳子。

这也是为什么 merge 前一定要想清楚“谁做主记录”。 因为主记录会决定很多最后留下来的字段语义。


四、为什么“先处理客户,再 convert”这么重要

_convert_and_allocate() 的顺序非常关键:

  1. _convert_handle_partner()
  2. lead.convert_opportunity(...)
  3. 再做 salesperson/team 分配

也就是说,Odoo 不希望先把 lead 转成 opportunity, 再回头想“客户是谁”。

它更偏向先把客户归属钉住:

  • 挂现有联系人
  • 或创建新联系人
  • 必要时带上 commercial_partner_id

然后再转换机会类型。

这背后是因为很多字段同步都依赖 partner:

  • 邮箱
  • 电话
  • 语言
  • 地址
  • 公司归属

如果 partner 没先落定,后面的 opportunity 语义就容易飘。


五、commercial_partner_id 不是装饰字段

很多实施顾问会忽略向导里的 company 选择,只盯着 contact。

但源码里 _convert_handle_partner() 会把:

  • force_partner_id
  • create_missing
  • with_parent=self.commercial_partner_id

一起交给 _handle_partner_assignment()

翻成业务话:

  • 你不只是在选联系人
  • 你还在决定这个联系人是不是要挂到某个上级公司下面

这会直接影响:

  • 新建联系人时的 parent company
  • commercial entity 归属
  • 后续重复判断和客户层级

所以如果 B2B 场景里公司层级很重要, 转商机时随手忽略 commercial_partner_id,后面数据会越来越乱。


六、负责人分配发生在转换之后,而且不一定强制

转换完成后,源码才开始看 force_assignment

逻辑是:

  • 如果 force_assignment=True,即使已有负责人,也可以改
  • 如果 force_assignment=False,只给尚未有负责人的机会分配

这解释了很多现场疑问:

为什么我选了 salesperson,结果有的机会没变?

因为你没有强制覆盖已有负责人。

为什么 team 会跟着 salesperson 变?

因为向导里 team_id 本来就会根据 user_id 重新求默认 team。

所以“转商机”界面的负责人选择,不只是显示值, 而是会影响转换后的承接 pipeline。


七、mass convert 和单条 convert 不是完全一回事

crm.lead2opportunity.partner.mass 额外加了两个关键语义:

  • deduplicate
  • each_exist_or_create

也就是说,批量转换时,Odoo 更倾向:

  1. 先对每条 lead 判断是否要 dedup
  2. 如果勾选了自动处理,就先 merge 重复项
  3. 再对每条 lead 单独判断“找现有客户 or 创建客户”

这其实很合理。

因为批量操作里最怕的是:

  • 一口气造出一堆重复 customer
  • 把重复 lead 各自转成多条机会

所以 mass convert 的核心目标不是“快”, 而是 在批量场景下尽量不把脏数据批量放大


八、实战里最容易误解的 5 件事

1. 以为 convert 只是类型切换

错。它本质上是客户归属和机会落位流程。

2. 以为 partner 一定是新建

错。源码默认优先复用已有 partner。

3. 以为 merge 是“保留全部信息”

错。merge 一定是主记录优先,其他记录会被吸收甚至删除。

4. 以为 salesperson/team 是最先决定的

错。源码是先处理 partner,再 convert,再分配。

5. 以为批量转换只是单条转换循环执行

不完全是。mass mode 有自己的 dedup 和 each-exist-or-create 语义。


九、一句话记忆法

Odoo CRM 转商机,先决定客户归谁、重复怎么收,再把 lead 变成 opportunity,最后才决定谁来接。

理解这个顺序,你就不会再把“转商机”当成一个简单按钮了。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。