CRM 深度

Odoo CRM 线索挖掘为什么不是把筛选条件发给 IAP 就完了:州白名单、credits 估算与 lead mining request 边界讲透

很多人把 Odoo CRM Lead Mining 理解成一个“把行业/国家条件发给 IAP”的外部搜索框,但 crm_iap_mine 真正做的是一层带预算意识的请求编排:州过滤不是所有国家都开放,联系人 credits 会按公司数放大,team/user 也会在提交前被先约束。

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

先说结论

Odoo CRM 的 Lead Mining 不是“把筛选条件丢给 IAP,然后等外部服务吐线索”。

crm.iap.lead.mining.request 在真正请求远端前,先做了三层业务约束:

  1. 把筛选条件收敛到服务能稳定理解的形状
  2. 提前估算 credits 成本,避免用户误以为联系人是白送的
  3. 把结果要落到哪个 team、哪个 salesperson、按 lead 还是 opportunity 建单先定好

所以这个模型本质上更像一个有预算意识的请求编排器,而不是单纯的 API 包装层。


一、为什么“州过滤”不是所有国家都开放

源码里最容易被忽略的是 _compute_available_state_ids()

它并不是简单按 country_ids.state_ids 把所有州/省都列出来,而是只对白名单国家开放州过滤。原因写得很直白:

  • 某些国家在 reveal 服务侧的州数据覆盖率很差;
  • 如果把这些州也放给用户选,查询结果会被意外压缩;
  • 用户会误以为“这个国家没有目标客户”,其实只是外部数据不完整。

这意味着 Odoo 的设计取向不是“让筛选器看起来更强”,而是优先保证筛选器不会误导业务判断

站在实施角度,这个细节很重要:

如果你在某些国家看不到州过滤选项,不一定是权限问题,也不一定是字段没配,而是产品故意收窄了过滤维度。


二、credits 为什么不是“公司数 + 联系人数”这么简单

_compute_tooltip() 的口径非常值得讲,因为它决定了销售和管理层对 IAP 成本的预期。

模型里有两组常量:

  • CREDIT_PER_COMPANY = 1
  • CREDIT_PER_CONTACT = 1

但真正的总成本不是简单相加,而是:

  • 找公司本身消耗 lead_number 个 credits;
  • 每家公司再额外追踪 contact_number 个联系人;
  • 所以联系人成本会按公司数放大。

也就是说,如果你请求:

  • 20 家公司,
  • 每家公司最多 5 个联系人,

那联系人成本不是 5,而可能是 20 × 5 = 100 的量级,再叠加公司本身的成本。

这就是为什么 tooltip 里会把“找公司”和“找联系人”拆开解释。Odoo 在这里防的不是技术错误,而是预算错觉

很多团队第一次开通 lead mining 时,最容易踩的坑就是:

  • 以为联系人只是“附带返回”;
  • 实际上联系人是按公司粒度放大的增量消耗。

三、search_typelead_type 是两条不同维度,不要混为一谈

源码把两个概念拆得很清楚:

  • search_type:外部要找“公司”还是“公司 + 联系人”;
  • lead_type:回到 Odoo 后,要落成 lead 还是 opportunity

这两个字段看起来都在讨论“线索类型”,但其实根本不是一回事。

search_type

决定 payload 里是否追加:

  • contact_number
  • contact_filter_type
  • preferred_role
  • other_roles
  • seniority

也就是说,它控制的是外部服务要挖多深

lead_type

决定结果回库时,crm.iap.lead.helpers.lead_vals_from_response() 最终建成 lead 还是 opportunity。

也就是说,它控制的是内部销售流程怎么接

很多项目里会把这两个选项一起解释成“你想不想要商机”,这是不准确的。一个更靠谱的理解是:

一个决定你向外买什么数据,一个决定你把买回来的数据放进哪条内部漏斗。


四、为什么 team 会在提交前就先回填,而不是建出来再分配

_compute_team_id() 的逻辑很像 Odoo 在很多业务模型里的典型风格:先限制合法落点,再允许用户提交

它会根据:

  • 当前 user_id
  • 当前 lead_type
  • team 是否启用 leads / opportunities

去挑一个默认 team。

如果你已经手工选了一个 team,且该用户确实属于这个 team 的负责人或成员,源码会保留你的选择;否则会重新找一个合法 team。

这背后的设计思路非常清晰:

  • Lead Mining 不是纯数据采购;
  • 它买回来的结果必须马上能被销售组织接住;
  • 所以组织归属不能拖到最后。

这也解释了为什么很多人感觉“我改个 salesperson,team 怎么跟着变了”:

因为 team 在这里不是展示字段,而是销售归属约束


五、请求真正发出去之前,Odoo 已经做了哪些收口

_prepare_iap_payload() 做的事情比表面看上去多:

  1. 把国家转成国家 code;
  2. 把州过滤压成对应国家下的 state code 列表;
  3. 行业标签把多个 reveal_ids 拆开并合并;
  4. people 模式下再补联系人角色或 seniority;
  5. 只在启用 size filter 时发公司规模上下限。

也就是说,Odoo 发给 IAP 的不是一份“表单原始值”,而是一份已归一化的业务查询描述

这对排错非常关键。

如果结果异常,不要只盯着界面字段显示对不对,而要问:

  • 这个字段有没有真正进 payload?
  • 是不是因为模式不同根本不会发?
  • 行业 reveal ids 是否被正确展开?

六、为什么错误处理只区分 creditsno_result

error_type 只保留两个显式枚举:

  • credits
  • no_result

这看起来很“粗”,但其实是产品层的刻意简化。

对业务用户来说,最关键的分支通常就两个:

  1. 钱不够,买不了
  2. 钱够,但这组条件没有命中结果

至于底层网络波动、服务端异常,源码会包成 UserError 抛回去,而不把这些技术细节长期保存在业务状态字段里。

这说明 Lead Mining 模型的状态机并不试图完整映射外部 API 的所有失败类型,而是只保留业务可决策的失败口径。


七、action_submit() 为什么先拿序列号,再决定是否重开当前表单

action_submit() 有个很像 Odoo 风格的小细节:

  • 第一次提交时先分配 request 编号;
  • 请求成功则建线索并跳到结果 action;
  • 请求失败且当前在 modal 中,则重新打开同一条记录;
  • 非 modal 下则直接刷新当前表单。

这背后的重点不是 UI,而是让失败仍然有上下文可追溯

也就是说,哪怕一次挖掘没有产出,这条 request 也不是一次性临时动作,而是一条可以回看、改条件、重新提交的业务记录。


八、实施里最容易误判的几个点

1. 看不到州过滤,就以为国家数据没维护

不一定,可能是产品为了避免低覆盖率误导,直接没开放州过滤。

2. 联系人成本被低估

很多团队只看“每联系人 1 credit”,却忘了它会按公司数放大。

3. 改 salesperson 后,team 自动变化被当成 bug

很多时候这是 _compute_team_id() 在帮你把记录拉回合法销售组织。

4. 没有结果就去怀疑 IAP 服务坏了

也可能只是条件太细、州过滤过窄、或 people 模式把结果集压扁了。


九、排错顺序建议

如果 Lead Mining 的结果和预期不一致,我会按这个顺序查:

  1. search_type 是 companies 还是 people;
  2. lead_number / contact_number 有没有被自动裁到上下限;
  3. country_ids 对应国家是否允许 state filter;
  4. 行业标签的 reveal_ids 是否完整;
  5. user_id 变化后 team 是否被重算;
  6. 错误属于 credits、不命中结果,还是底层异常。

一句话记忆

Odoo CRM Lead Mining 真正管的不是“怎么搜公司”,而是“用什么预算、以什么组织归属、向 IAP 发一份不会误导业务的请求”。

DISCUSSION

评论区

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