先说结论
Odoo 在线聊天里看到“这个访客关联了哪些商机”,并不是前端自己拿 partner 再临时查一遍 CRM。
真正的机制是:
- livechat session 会通过 store 向前端下发一组可显示字段;
crm_livechat只在当前用户有crm.lead读取权限时,才把livechat_customer_partner_ids.opportunity_ids这一层加进去;- 如果没有权限,这块结构根本不会发给前端。
所以这里的关键不是“前端显示了什么”,而是:
后端先决定什么数据有资格进入聊天会话快照。
一、为什么这件事发生在 session store,而不是聊天窗口自己再发请求
_get_livechat_session_fields_to_store() 的意义,在于它定义了“当前 livechat 会话允许带给前端的数据轮廓”。
这和常见的“前端打开侧栏后再单独请求一份 CRM 数据”很不一样。
Odoo 选 store 模式有几个明显好处:
- 会话初始化时一次性带齐必要数据;
- 实时 UI 不用再自己拼权限逻辑;
- 聊天前端只消费已授权的数据,不再重复发散查询。
换句话说,商机可见性在这里不是一个“展示层功能”,而是会话快照的一部分。
二、为什么没有 crm.lead 读取权时,不是“显示空列表”,而是整个字段都不发
源码里最关键的一行其实是:
- 先拿父类的
fields_to_store; - 如果
self.env["crm.lead"].has_access("read")不成立,直接 return。
这意味着 Odoo 的选择不是:
- 把
opportunity_ids作为空数组下发; - 再让前端自己理解“你没权限,所以是空的”。
而是更彻底地:
- 你没有权限,就别收到这块字段定义。
这两者差别很大。
前者只是把结果清空,后者则是在协议层就声明“这段数据结构不属于你”。
这是一种更干净的安全模型,因为它避免了前端去推断:
- 到底是真的没有商机;
- 还是有商机但你没权限;
- 还是接口坏了。
Odoo 这里选的是最保守、也最清楚的一条线。
三、为什么要通过 Store.Many 暴露到 livechat_customer_partner_ids.opportunity_ids
Store.Many 暴露的是一个嵌套关系:
- 先是当前 livechat 里的客户 partner;
- 再是这个 partner 对应的
opportunity_ids; - 且
only_data=True,只下发纯数据。
这说明 Odoo 要给坐席的不是一大坨 CRM 详情,而是一个足够轻、足够快、足够可行动的关联视图。
它想解决的问题是:
- 这个来访者是不是已经在 pipeline 里;
- 坐席要不要按已有商机语境接话;
- 有没有必要把人再重复建成新线索。
也就是说,这里暴露商机不是为了“在聊天里浏览 CRM”,而是为了让客服/销售在会话当下做更准确的判断。
四、为什么这套机制能减少前台越权和误导
如果没有这层 store 裁剪,常见的坏味道会很多:
- 前端知道 partner id,就想自己再调 CRM 接口;
- 不同聊天角色拿到的数据结构不一致,却没有统一权限出口;
- UI 上看起来像是“没有商机”,其实只是因为权限被拦在另一个接口。
现在因为机会信息是否存在,是由 store 构建阶段统一决定:
- 权限判断只在服务端做一次;
- 前端要么拿到这块数据,要么根本没有这块字段;
- 聊天窗口显示语义更稳定。
这其实是把“安全”和“可维护性”一次性都解决了。
五、为什么这不等于“有权限的人就能看到所有 CRM 内容”
这里也要注意一个常见误解。
_get_livechat_session_fields_to_store() 暴露的是:
- customer partner 下的
opportunity_ids; - 并不是把完整 lead / opportunity 表单字段通通搬进聊天窗口。
这意味着 Odoo 在做的是最小必要暴露:
- 先告诉你“有无商机、哪些商机”;
- 而不是直接把 CRM 全量详情塞进会话。
这套收口很合理,因为在线聊天场景要求的是快速判断,不是完整审阅后台记录。
六、实施里最容易误判的几个点
1. 以为机会列表是前端自己算出来的
不对,它是后端 session store 明确下发的。
2. 以为没看到商机就说明客户没有历史机会
不一定,也可能是当前用户没有 crm.lead 读取权。
3. 以为权限不足时会收到空数组
不是,很多时候是整块字段结构根本不会出现。
4. 以为聊天窗口会暴露完整 CRM 详情
不会,Odoo 只下发最小必要的关系数据。
七、排错顺序建议
在线聊天里看不到客户商机时,我建议按这个顺序查:
- 当前坐席是否具备
crm.lead读取权限; - 当前 livechat session 是否绑定到了 customer partner;
- store 快照里是否存在
livechat_customer_partner_ids.opportunity_ids; - partner 本身是否真的有关联商机;
- 前端是否把“字段不存在”和“字段为空”误当成同一回事。
一句话记忆
Odoo 在线聊天里的商机可见性,不是前端想看什么就查什么,而是后端 session store 先按 CRM 权限把会话数据裁好再发。
DISCUSSION
评论区