其他深度

Odoo 活动报名为什么不是“填个名单就完了”:slot、ticket、参会人资料同步与席位校验链路讲透

很多人以为 Odoo 活动报名只是收集姓名和邮箱,但 event.registration 实际把场次、票种、联系人同步、条码签到和席位校验串成了一条完整业务链。看懂这条链,活动运营才不会在报名扩容和现场签到时翻车。

其他
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

先说结论

Odoo 的活动报名不是一张“报名表”,而是一条把售卖、报名、签到、场次容量和参会人信息连起来的业务链。

/home/ubuntu/odoo-temp/addons/event/models/event_registration.pyaddons/event_sale/models/sale_order.py 来看,event.registration 至少承担了五件事:

  • 绑定具体活动 event_id
  • 在多场次活动里绑定 event_slot_id
  • 在售票场景下绑定 event_ticket_id
  • 同步联系人姓名、邮箱、电话、公司信息
  • 用状态与条码支撑签到和席位控制

所以它真正解决的问题不是“有人来报名”,而是:

每一个报名人,到底报了哪个活动、哪个场次、哪种票、占不占座位、现场怎么识别、后续如何统计。


第一层:报名记录为什么必须挂在活动、场次和票种上

event.registration 里最关键的三组字段就是:

  • event_id
  • event_slot_id
  • event_ticket_id

这说明 Odoo 从一开始就不把“报名”理解成一个泛联系人清单,而是理解成:

  • 某人报名了某个活动
  • 如果活动分多个场次,还要知道他具体去哪一场
  • 如果活动分票档,还要知道他买的是哪种票

这三个维度一旦没分清,后面的运营动作都会变得含糊:

  • 剩余席位算不准
  • 不知道哪一场超卖
  • 统计营收时票档无法拆分
  • 现场签到时容易把不同场次的人混在一起

源码里 _check_event_slot_check_event_ticket 也正是在守这个边界:

  • 场次必须属于当前活动
  • 票种也必须属于当前活动
  • 多场次活动里,场次不能空着

这不是“字段校验很严格”,而是在防止业务对象串台。


第二层:为什么报名信息会自动继承联系人资料

很多实施项目里都会遇到一个问题:

  • 报名时的联系人已经存在于通讯录
  • 但活动报名又想记录参会人的姓名、邮箱、电话、公司
  • 如果全都人工再填一遍,体验会很差

Odoo 在 event.registration 里用一套 _compute_name_compute_email_compute_phone_compute_company_name 来处理这个问题。

核心思路不是简单地“复制 partner 字段”,而是通过 _synchronize_partner_values() 去找更贴近联系人的地址对象,尽量拿到适合活动沟通的值。

这背后的产品判断很实用:

  • 联系人主数据负责长期身份
  • 报名记录负责这次参会上下文

所以报名记录会参考联系人,但又不完全等于联系人本身。

这就是为什么活动运营里常见的这些场景能成立:

  • 公司联系人统一采购门票
  • 实际参会人资料再按报名记录细化
  • 后续邮件通知仍然能基于报名记录发出

第三层:为什么系统还要给每个报名生成 barcode

barcode 字段默认来自 _get_random_barcode(),而且源码注释写得很清楚:

  • 它不是随便生成一个字符串
  • 还考虑了条码序列化后在扫描器里的兼容性

这意味着 Odoo 的报名模型默认就考虑到了现场签到

也就是说,报名不只是后台台账,还面向现场执行:

  • 提前邮件发送凭证
  • 现场扫码确认到场
  • 避免只靠姓名搜索导致重名和误判

很多人会低估这件事,以为活动系统只要把名单导出来就行。 但从源码角度看,官方显然希望你把活动当成一条完整闭环:

  • 报名前台采集
  • 中台分场次与票种
  • 现场条码识别
  • 报名状态回写

这比“Excel 名单 + 手工勾选”高一个层级。


第四层:席位校验为什么要在报名对象上做

_check_seats_availability() 很值得看。

它会筛出:

  • 状态为 opendone
  • 且仍然 active 的报名

然后按活动去聚合当前报名占用,再调用活动侧的 _verify_seats_availability()

这表示 Odoo 的席位逻辑不是只在“卖票时”检查一次,而是把报名对象本身当作席位占用的真实来源。

这样设计有几个好处:

1. 已签到和已注册都算席位占用

只要状态是有效参会状态,就应当占容量。

2. 取消或归档的报名可以被排除

活动主办方临时释放席位时,逻辑上更清楚。

3. 多场次 + 多票档可以一起核算

因为聚合键里已经考虑了 slot 和 ticket 的组合。

这也是为什么活动扩容、补票、人工调报名时,实施顾问不能只盯前台售票页面,更要看报名记录状态有没有被正确维护


第五层:销售订单为什么会反向影响报名记录

event_sale/models/sale_order.py 里,sale.order.write() 有一个很有代表性的动作:

  • 如果订单里存在活动类行
  • 且订单联系人变了
  • 系统会去把相关 event.registrationpartner_id 一起更新

这说明在 Odoo 看来,活动报名和销售订单不是松耦合关系,而是同一笔业务的两个视角

  • 订单负责交易
  • 报名负责参会执行

此外,action_confirm() 里还会做两件关键事:

  • 校验活动相关销售行是否都配置了事件
  • 调用 _init_registrations() 正式生成报名记录

换句话说:

买票不是报名的旁路,而是报名生成链路的一部分。

这对做收费活动非常关键,因为它保证了“卖了几张票”和“生成了几个有效参会名额”之间有明确对应关系。


最容易误解的三个点

误区一:把报名当静态联系人表

如果把 event.registration 当成一次性联系人列表,你会忽略:

  • 状态
  • 场次
  • 票种
  • 席位
  • 条码

最后现场执行和统计都会出问题。

误区二:觉得联系人信息改了,报名自然全都对

报名会参考联系人,但它是活动语境下的快照对象。 如果历史报名、代报名或企业团购很多,不能指望“改一处 partner 就永远正确”。

误区三:只在售票环节看容量

真正决定容量是否被占用的,是报名记录及其状态,而不只是电商下单动作。


实战上该怎么理解这张表

可以把 event.registration 理解成活动业务里的“执行单”。

它向前接:

  • 官网报名
  • 销售订单
  • 票种与价格

它向后接:

  • 签到
  • 到场状态
  • 报表分析
  • 邮件通知

因此做活动项目时,最稳的做法不是只盯前台报名表,而是顺着这条链检查:

  1. 活动是否配置了正确场次和票种
  2. 销售行是否能正确生成报名
  3. 报名是否同步到合适联系人
  4. 席位是否按有效状态正确占用
  5. 条码和签到流程是否能闭环

最后一句

Odoo 活动报名的价值,不在于它帮你“收集名单”,而在于它把一场活动拆成了可执行、可控制、可统计的对象。

当你把 event.registration 看成这条链的中心节点,很多设计就不再奇怪了:

  • 为什么要有场次
  • 为什么要有票种
  • 为什么要校验席位
  • 为什么要有条码
  • 为什么订单和报名要互相联动

因为活动管理真正难的,从来不是“有人报名”,而是报名之后怎么不乱。

DISCUSSION

评论区

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