企业 电话协同

Odoo 企业版 VoIP 为什么不是“点号码就打”:外设回拨、移动端拨号偏好、未接来电计数与最近通话同步讲透

基于 voip 源码,讲清 Odoo 企业版电话体验为什么不是浏览器里直接拨号:系统会把外设回拨、移动端默认电话 app、未接来电计数、last_seen_phone_call 与最近通话 Store 同步串在一起,让桌面端、手机端与 PBX 侧形成同一套通话上下文。

企业 协同办公
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 4 阅读

很多人第一次看 Odoo 企业版 VoIP,会把它理解成“在联系人上点个号码,用浏览器打出去”。

但如果你认真读 enterprise/voip,会发现官方真正实现的不是“网页拨号器”,而是一套跨终端电话上下文:

  • 这通电话到底从浏览器软电话发起,还是让别的设备回拨;
  • 在手机上点号码时,是继续用 Odoo Phone,还是跳系统电话 App;
  • 未接来电计数怎么避免一直累加;
  • 最近通话记录如何回到前端侧边栏并和当前用户状态对齐。

所以这篇文章想讲清的是:

Odoo 企业版 VoIP 不是“点号码就打”,而是把桌面端、移动端和 PBX 之间的终端选择权与通话状态同步做成了一条协同链。

一、res.users 上那些 VoIP 字段,核心目的不是存配置,而是把“用户偏好”接进受控权限模型

enterprise/voip/models/res_users.py 里,官方把一组 VoIP 字段挂在 res.users 上:

  • external_device_number
  • how_to_call_on_mobile
  • should_call_from_another_device
  • voip_provider_id
  • voip_secret
  • voip_username

但源码又明确说明:这些字段真正定义在 res.users.settings 上,只是通过 compute / inverse 映射到 res.users

为什么要绕这一层?

因为官方想同时满足两件事:

  1. 用户在常见的用户设置入口里就能改自己的电话偏好;
  2. 这些偏好又不要直接暴露成普通 res.users 字段那种统一访问权限模型。

所以 _get_voip_user_configuration_fields()SELF_READABLE_FIELDSSELF_WRITEABLE_FIELDS_reflect_change_in_res_users_settings() 这一整套设计,本质是在说:

  • VoIP 偏好是“用户可自助维护的敏感配置”;
  • 它需要被 UI 读写,但又要有比普通用户字段更精细的边界。

二、“从另一设备拨出”不是附加功能,而是 Odoo 对真实办公环境的默认承认

res.users.settings 里有两个很关键的字段:

  • should_call_from_another_device
  • external_device_number

help 文案已经把意图写透:

在 Odoo Phone 发起电话时,先响你的桌机或手机,再把你接到目标号码。

这说明 Odoo 从一开始就没把企业电话场景想成“所有人都戴耳机,在浏览器里直接 SIP 通话”。

相反,它承认大量企业用户真实的工作方式是:

  • CRM 在电脑上看;
  • 通话仍然通过桌面电话、分机、手机来接;
  • 但通话动作和上下文希望从 Odoo 发起。

所以“call from another device”不是边角功能,而是桌面业务界面与实体电话终端之间的桥

三、移动端点号码时,为什么还要问“用 Odoo Phone 还是系统电话 App”

res.users.settings 里还有一个非常有代表性的字段:how_to_call_on_mobile

可选值是:

  • voip:用 Odoo Phone
  • phone:用系统默认电话 App
  • ask:每次都问

这就表明 Odoo 并不强迫移动端一定走自己的 VoIP 客户端。官方承认移动办公有至少三种现实:

  1. 企业已经把 Odoo Phone 当主入口;
  2. 员工更习惯系统拨号器;
  3. 某些号码、场景或网络状态下,用户希望当下再决定。

因此移动端拨号偏好被做成了用户级配置,而不是管理员全局硬编码。

对协同办公来说,这种设计特别合理,因为它把“业务入口统一”和“终端能力差异”同时保住了。

四、voip.call.create_and_format() 说明最近通话不是日志,而是前端状态对象

enterprise/voip/models/voip_call.py 里的 create_and_format() 很关键。

它不只是创建一条 voip.call 记录,而是立刻返回:

  • 新建 call 的 ids;
  • 一份通过 Store().add(...)._get_result() 组出来的前端消费数据。

如果传了 res_model + res_id,它还会去相关记录上做 _mail_get_partners(introspect_fields=True),自动推导 partner。

这说明最近通话面板在 Odoo 里并不是“数据库里有条记录,前端下次刷新时自己查”。

而是:

创建电话事件的同时,系统就把它格式化成一份可立即注入前端状态树的数据。

这也是为什么企业版 VoIP 用起来更像一个持续在线的电话工作台,而不是后台电话日志列表。

五、未接来电计数为什么要依赖 last_seen_phone_call

res.users 上有一个字段:last_seen_phone_call

配套方法 reset_last_seen_phone_call() 会把它更新成当前用户最近的一条电话记录;而 _get_number_of_missed_calls() 则只统计:

  • 当前用户的 voip.call
  • state = 'missed'
  • 且如果存在 last_seen_phone_call,只算其后的记录。

这套逻辑的意义非常大。

它说明未接来电 badge 并不是“把所有 missed 累积求和”。系统真正想表达的是:

  • 自从你上次看过电话面板之后,又新增了多少未接来电。

这就避免了一个很常见的企业电话问题:

  • 历史 missed call 永远存在;
  • badge 永远不归零;
  • 用户最后彻底忽略它。

通过 last_seen_phone_call 作为边界,Odoo 把未接来电计数做成了“增量提醒”,而不是“历史总账”。

六、_get_voip_config() 把这些终端选择和提醒状态一次性喂给前端

res.users._get_voip_config() 会返回一组前端全局配置:

  • callActivityTypeId
  • mode
  • missedCalls
  • pbxAddress
  • recordingPolicy
  • webSocketUrl

这里的 missedCalls 就来自 _get_number_of_missed_calls()

也就是说,前端启动时拿到的并不是零散字段,而是一份已经汇总好的 VoIP 运行配置:

  • 当前 PBX 怎么连;
  • 通话录音政策是什么;
  • 现在还有多少未接电话需要提醒。

这让 VoIP 前端工作台能在打开时就进入“可拨打、可提醒、可联动”的状态,而不是再额外发很多请求拼配置。

七、最容易误解的地方

1. “VoIP 就是网页里直接打电话”

不对。源码明确支持先呼叫外部设备,再接通目标方,这正是大量办公室场景真正的通话模式。

2. “移动端点号码时,系统应该统一强制走 Odoo Phone”

也不对。Odoo 专门把 how_to_call_on_mobile 做成 ask / voip / phone 三档,是因为移动终端能力和用户习惯本来就不统一。

3. “未接来电计数就是 missed 状态总数”

不是。它是以 last_seen_phone_call 为界的增量提醒。

八、实战建议

如果客户说“电话面板的未接计数不对”或“为什么手机点号码时行为不一致”,我会先看:

  1. 用户 res.users.settingshow_to_call_on_mobileshould_call_from_another_deviceexternal_device_number 的当前值;
  2. res.users 是否已经通过 inverse 正确回写到 settings;
  3. last_seen_phone_call 是否在用户查看电话面板后正确更新;
  4. 前端启动时拿到的 voipConfig.missedCalls 是否与数据库状态一致;
  5. 当前 provider 的 modepbxAddresswebSocketUrl 是否可用。

这比单看一条通话记录更接近问题根源。

九、结论

Odoo 企业版 VoIP 做得最像企业协同工具的地方,不是 SIP 或 WebSocket 本身,而是它承认:

  • 人可能在电脑里发起业务动作;
  • 真正接电话的却是桌机或手机;
  • 用户需要在移动端保留拨号选择权;
  • 未接提醒必须围绕“上次看过之后的新变化”来计算。

所以它不是“点号码就打”,而是一套围绕终端切换、用户偏好与状态同步组织起来的电话协同链路。

DISCUSSION

评论区

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