企业版预约

Odoo 企业版 Website Appointment 为什么不是“放个预约页”而已:发布态、操作员选择与 visitor fallback 边界讲透

很多人把 Odoo 企业版网站预约理解成“把 appointment.type 暴露到前台”。真正看 website_appointment 源码会发现,官方处理的是一整套网站语义:预约类型既是 appointment 对象,又是 website 发布内容;前台有操作员/资源选择分流;公开访客没有账号时,还会用 website visitor 兜底时区、国家与客户识别。

企业 网站
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 8 阅读

很多人第一次看 Odoo 企业版 Website Appointment,会把它想成一个很简单的动作:

  • 后台建一个 appointment type;
  • 网站上给它一个链接;
  • 用户选时间提交。

这个理解只覆盖了“前台表单”层面,没覆盖“网站内容对象”层面。

website_appointment 的 model、controller 和测试串起来看,会发现官方真正做的是:

把 appointment.type 同时做成“可预约对象”和“网站发布对象”,再围绕公开访客场景补上一整套兜底识别逻辑。

这里最值得看的有四条线:

  1. 预约类型的发布语义
  2. 网站前台的操作员/资源选择流
  3. 公开访客的时区、国家、客户识别 fallback
  4. 多公司/多网站下的前台域名与公司边界。

一、appointment type 在这里不只是业务对象,还是 website 内容对象

website_appointmentappointment.type 做了多重继承:

  • website.seo.metadata
  • website.published.multi.mixin
  • website.searchable.mixin

这说明它不只是后台预约配置,而是能被:

  • 发布到网站;
  • 进入站内搜索;
  • 挂 SEO 元数据;
  • 生成 website_url。

_compute_website_url() 直接把它映射成:

  • /appointment/<id>

所以 appointment type 在网站场景里,已经不只是“可被预约”,而是“可被公开浏览、搜索、索引、分享”。

这就是为什么 Website Appointment 不是普通业务表单,而是内容+业务混合对象。


二、为什么复制 appointment type 要强制取消发布

copy_data() 在复制时会强制把 is_published=False

这点很关键。

因为如果复制一个已经上线的预约类型,而系统默认让副本继续公开:

  • 很容易把还没调好的副本暴露到网站;
  • 也可能制造重复入口或错误预约页。

官方在这里的态度非常保守:

复制是后台编辑动作,不应自动继承前台可见性。

这和很多 CMS/电商对复制内容默认下线的思路一致。


三、为什么预约首页不是简单列表,而会按筛选结果直接跳转

controller 的 appointment_type_index() 会:

  • 先按网站域、搜索词、invite token 等拼 domain;
  • 再过滤 private appointment type;
  • 如果最后只剩一个可用类型且没有搜索词,直接跳详情页。

这说明首页的职责不是永远给你一个目录,而是:

  • 多个可选时做选择页;
  • 只有一个可选时,直接缩短用户路径。

这很像典型网站漏斗优化,而不是后台菜单思维。


四、为什么前台会多一个“操作员选择页”

_get_appointment_type_page_view() 会根据条件决定是不是先展示 operator selection 页面。

触发条件大意是:

  • 当前 appointment type 不是 auto assign;
  • 不是 date-first;
  • 还没选定 user/resource;
  • 且可选用户或资源不止一个。

这说明 Odoo 不是默认把“选谁服务”塞进一个下拉框,而是:

在更适合的网站场景下,把它升级成一张专门的前台选择页。

尤其是基于 users 调度时,前台可以展示:

  • 头像;
  • 职位;
  • 网站描述。

这已经明显是网站转化体验设计,而不只是业务表单字段渲染。


五、为什么还要支持 skip_resource_selection

虽然有专门的操作员选择页,但系统又保留了 skip_resource_selection

这代表官方并没有把“先选人再选时段”当成唯一正解,而是承认两种漏斗:

  1. 先选人 / 资源,再看空档
  2. 先看全局可预约时段,再决定由谁承接。

如果用户选择跳过,controller 会把:

  • user_selected
  • resource_selected
  • user_default
  • resource_default

清成空 recordset,让页面回到“看全量可用时间”的模式。

所以 Website Appointment 的前台流程是可分流的,不是固定单路径。


六、为什么公开访客没有账号时,时区还不会乱掉

create_and_get_website_url() 有一个很值得读的兜底:

  • 如果没传 appointment_tz
  • 先看当前用户时区;
  • 没有的话再看 website.visitor.timezone
  • 再不行才退回 UTC

测试也明确覆盖了这三层 fallback。

这说明 Odoo 很清楚网站预约常见场景是:

  • 访客未登录;
  • 公共用户没有稳定个人配置;
  • 但预约时间展示仍必须尽量贴近访客所在地时区。

所以前台时区不是“依赖登录用户”,而是“依赖 visitor 画像兜底”。

这点在公开网站尤其重要。


七、为什么客户识别也会回退到 visitor 和历史预约

_get_customer_partner() 的逻辑很有意思。

如果标准路径没找到 partner,它会继续尝试:

  1. 当前 visitor 的 partner_id
  2. 如果 visitor 没 partner,但当前是 public user,找这个 visitor 最近一次预约事件上的 appointment_booker_id

这说明 Odoo 想避免的不是“找不到客户”,而是:

同一个公开访客反复预约时,不要不断新建重复 partner。

也就是说,visitor 在这里不是流量统计对象,而是 前台客户连续性锚点


八、为什么国家也会从 visitor 回填

_get_customer_country() 先走标准定位逻辑,如果没命中,再回退到 website.visitor.country_id

这和时区 fallback 是同一个设计思想:

  • 网站用户可能没有登录;
  • 也可能地理库没命中;
  • 但预约类型本身可能受国家限制。

因此 visitor 上已有的国家信息就变得很关键。

这保证了:

  • 网站筛选 appointment type;
  • 或前台默认国家值;

不会因为缺登录态就全面失效。


九、为什么 recaptcha 校验放在提交入口,而不是页面展示时

appointment_form_submit() 在真正提交时才做:

  • _verify_request_recaptcha_token('appointment_form_submission')

这说明官方防的是:

  • 机器人伪造提交;
  • 而不是单纯阻止页面访问。

所以预约页本身仍然可以公开浏览,但真正落单动作必须过验证码校验。

这是一种很标准、也很克制的公开表单防滥用边界。


十、为什么多网站下视频会议链接还要看 appointment 对应 website

测试里专门验证了:

  • 不同 website/domain 下的 appointment type;
  • 生成的 videocall 链接要匹配对应网站域名;
  • 即使事件读取者本身未必有 appointment type 读取权限,也要能拿到正确 base url。

这说明 Website Appointment 不是“后台用哪个 base_url 就统一拼”。

而是:

前台预约对象属于哪个 website,就应该从哪个网站域名对外表达。

这在多公司、多站点环境下非常关键。


十一、实战里最容易误解的 4 个点

误区 1:appointment type 只是后台预约配置

不是。

在这里它同时是网站发布内容。

误区 2:操作员选择只是下拉框 UI 差异

也不对。

它决定了网站预约漏斗是“先选人”还是“先看片段时间”。

误区 3:公开访客没有账号,就没法做可靠识别

不对。

visitor 提供了时区、国家和客户回连兜底。

误区 4:多网站下预约链接只要系统能打开就行

不行。

面向访客的 URL 和视频会议入口必须跟 appointment 所属网站一致。


总结

website_appointment 串起来看,你会发现 Odoo 企业版做的根本不是“给预约类型一个网站页”。

它真正做的是一套前台预约站点机制:

  • website mixins 把 appointment type 升级成可发布内容;
  • operator/resource selection 组织前台预约漏斗;
  • skip_resource_selection 支持不同预约路径;
  • website visitor 为时区、国家和客户身份做兜底;
  • recaptcha 守住公开提交入口;
  • website/domain 对齐 保证多网站前台体验正确。

所以 Odoo 企业版 Website Appointment 的本质,不是“预约表单上网站”,而是“把预约能力真正产品化成一个公开网站流程”。

这才是这部分源码最值得学的地方。


参考源码 - enterprise/website_appointment/models/appointment_type.py - enterprise/website_appointment/controllers/appointment.py - enterprise/website_appointment/tests/test_appointment.py

DISCUSSION

评论区

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