先说结论
Odoo 的活动报名,真正难的从来不是“有人填了表”,而是:
- 你收集的问题到底是给谁回答的
- 同一笔团体报名里哪些答案应该复用
- 报名后什么时候该进 CRM,什么时候还不该
- 现场扫码时遇到错场、取消单、草稿单,系统怎么防误放行
从 /home/ubuntu/odoo-temp/addons/event/models/event_question.py、addons/event/models/event_registration.py 和 addons/event_crm/models/event_lead_rule.py 来看,Odoo 其实把这件事拆成了三层:
- 问卷采集层:
event.question - 报名执行层:
event.registration - 销售跟进层:
event.lead.rule
所以活动报名不是一条“报名成功”消息,而是一条从资料采集、资格确认到销售跟进和签到核验的链路。
第一层:活动问题为什么不是随便加几个字段
event.question 里最值得注意的不是标题,而是 question_type 和 once_per_order。
问题类型内置了:
simple_choicetext_boxnameemailphonecompany_name
这说明 Odoo 不把报名问卷理解成一堆无结构备注,而是把它当成可被分析、可被复用、可被后续流程消费的输入。
尤其 once_per_order 很关键。
它解决的是团体报名里一个非常常见的场景:
- 公司统一下单 10 张票
- 联系公司、开票抬头、赞助套餐编号这些信息,其实整单只需要填一次
- 但参会人姓名、邮箱、手机号,又必须逐人区分
如果系统没有这个边界,运营端很快就会遇到两个问题:
1. 同一订单重复问十次相同问题
前台体验会很差,放弃率会上升。
2. 后台答案结构被污染
明明是“订单级信息”,却被硬塞成“参会人级信息”,后续分析完全不准。
所以 once_per_order 并不是一个小优化,它是在明确:
有些答案属于一整笔报名,有些答案只属于某个参会人。
第二层:为什么已经被回答的问题不能随便改类型或删除
event.question.write() 里有一个很硬的限制:
- 如果题目已经产生过
event.registration.answer - 就不能再改
question_type
同时删除时也有限制:
- 已经被回答过的问题不能删,只能归档
- 默认问题也不能删除
这背后的产品判断非常成熟。
因为一旦报名答案已经落库,题目就不再只是“表单配置”,而是历史数据结构的一部分。
比如原来是:
- 单选题:你来自哪个行业?
后来你想改成:
- 文本题:请描述你的行业背景
从业务感觉上像“只是换一种问法”,但从数据结构上,这已经不是同一个字段了。
如果允许强改,后果会很现实:
- 老数据无法和新数据一起统计
- 报表图表会出现混乱分类
- 已有报名答案会和题型语义不匹配
所以 Odoo 的选择不是“给管理员更多自由”,而是优先保护历史报名数据的可解释性。
这也是为什么成熟活动系统都不鼓励在活动已经开卖后频繁改问卷。
第三层:为什么问卷分析入口要按题型切不同视图
action_view_question_answers() 也很值得看。
它不是一刀切地给你一张列表,而是:
simple_choice走 graph / pivot / listtext_box走 list
这说明 Odoo 对报名问题的期待不是“收集完算了”,而是希望运营者真正拿它做分析。
这背后其实对应两类完全不同的运营动作:
选择题
适合做结构化分布判断,比如:
- 参会人主要来自哪个行业
- 哪个岗位报名最多
- 对哪个议题兴趣最高
文本题
适合做人工筛选、销售补充判断、活动前人工分层。
比如:
- 你希望和哪类合作伙伴对接
- 你当前最关心的业务挑战是什么
所以 Odoo 不是把题目都塞进同一个答案表里让你自己想办法,而是默认承认:
报名问题本身就是后续运营的输入,不同题型就该有不同消费方式。
第四层:报名什么时候该进 CRM,不是固定答案
很多团队一看到活动报名,就会问:
- 能不能一报名就自动建线索?
Odoo 的回答不是简单的“能”或“不能”,而是给了 event.lead.rule 一套规则引擎。
最核心的两个维度是:
创建基准 lead_creation_basis
attendee:按参会人逐个建线索order:按订单/报名批次聚合建线索
触发时机 lead_creation_trigger
create:报名一创建就触发confirm:报名进入 registered/open 时触发done:签到到场后再触发
这套设计非常贴近真实业务。
B2C 活动
更适合 per attendee。
因为每一个参会人自己就是跟进对象。
B2B 招商会或企业专场
更适合 per order。
因为真正有业务价值的,往往是这一整批报名背后的公司或采购主体。
高噪音活动
不适合 create
比如公开直播、大流量峰会,报名量很大,但质量参差不齐。如果一创建就灌 CRM,销售团队会被低质量线索淹没。
高意向闭门会
更适合 confirm 或 done
因为你更关心“真正锁定席位的人”或“真正到场的人”。
也就是说,Odoo 这里最重要的设计不是自动建线索,而是:
让活动团队自己定义,哪一刻的报名才配得上线索。
第五层:为什么线索规则还要支持 domain 过滤
event_registration_filter 支持 domain,这个细节特别实用。
它意味着你不是只能按“某个活动”生成线索,而是可以进一步筛掉不值得进入销售池的人。
比如你完全可以做出类似规则:
- 只给 VIP 票种建机会
- 只给填写了特定采购意向的报名建线索
- 只处理某个公司、某个活动模板或某类来源的报名
这件事的价值在于:
1. 活动报名和销售跟进终于不再一刀切
不是所有报名都值得销售一视同仁追。
2. 报名问卷开始真正服务 CRM
问卷不再只是运营收集信息,而可以变成线索分层条件。
3. 现场签到可以成为二次筛选门槛
对某些活动,真正值得进销售漏斗的不是“报名过的人”,而是“真的来过的人”。
这也是为什么 done 触发在源码里被明确支持。
第六层:现场签到为什么一定要有异常状态分流
event.registration.register_attendee(barcode, event_id) 是一段非常典型的现场兜底逻辑。
扫码后它不会直接一律签到成功,而是先判断一整套状态:
- 条码不存在:
invalid_ticket - 报名已取消:
canceled_registration - 报名未确认:
unconfirmed_registration - 活动已结束:
not_ongoing_event - 扫到的是别的活动:
need_manual_confirmation - 已经签到过:
already_registered - 正常可签到:
confirmed_registration
这个设计说明 Odoo 很清楚:
现场签到不是数据库查到一条记录就放人进场。
而是要同时判断:
- 这张票是不是有效
- 这场活动是不是还在进行
- 这个人是不是报对了场次
- 这个人是不是已经被处理过
尤其 need_manual_confirmation 非常关键。
它处理的是现场最容易翻车的一种情况:
- 条码是真条码
- 人也确实报过活动
- 但扫票设备或签到点当前对应的 event_id 不一致
这时系统没有粗暴报错,也没有直接放过,而是要求人工确认。
这就是成熟线下执行逻辑该有的样子:
宁可把异常分流给前台人工处理,也不要让系统假装一切正常。
第七层:已签到为什么还要写 attended log
在 write() 里,如果状态被写成 done,系统会记录一条 attended message。
很多人会觉得这只是 chatter 小细节,但它其实很重要。
因为到场并不只是状态变化,它往往会触发:
- 会后销售跟进
- 二次营销名单
- 到场率统计
- CRM 机会晋级
- 复盘时的责任追溯
如果系统只保留一个当前状态,没有明确时间语义,后续很多分析都会模糊。
活动系统最怕的不是数据少,而是“都在,但不知道什么时候发生”。
实施时最容易踩的四个坑
误区一:所有问题都按参会人问
错。 公司、预算区间、团体需求这类信息,很多时候应该是订单级问题。
误区二:活动开始卖票后还频繁改问卷
错。 一旦已有答案,题型和结构就应该尽量稳定。
误区三:所有报名一律自动进 CRM
错。 线索生成时机和粒度,要跟活动类型匹配。
误区四:签到系统只要扫到条码就放行
错。 现场最重要的是异常状态分流,而不是“全部自动化”。
最后一句
Odoo 活动报名最容易被低估的地方,不是票种,也不是人数统计,而是它把问卷、报名、CRM、签到异常串成了一条真正可执行的链。
所以如果你要把活动做稳,别只问“能不能报名成功”,更该问这四件事:
- 问题是不是按正确粒度设计
- 答案能不能长期分析
- 线索是不是在正确时机进入 CRM
- 现场扫码遇到异常时有没有清晰分流
把这四层守住,活动后台才不会看起来热闹,实际上全是脏数据。
DISCUSSION
评论区