先说结论
Odoo 的活动展位不是“场地图上的一个格子”,而是一个把可售资源、客户占用、官网曝光、赞助商身份和活动通知连起来的运营对象。
从 /home/ubuntu/odoo-temp/addons/event_booth/models/event_booth.py 和 addons/website_event_booth_exhibitor/models/event_booth.py 来看,event.booth 至少承担了四层职责:
- 记录一个展位属于哪个活动
event_id - 用
state区分展位是否可售、是否已被占用 - 把租户
partner_id的联系人资料同步到 booth 自身 - 在启用 exhibitor / sponsor 扩展时,自动衍生出
event.sponsor
所以它真正要解决的问题不是“谁租了这个位子”,而是:
一个展位从招商、确认、官网展示到后续传播,是否始终围绕同一个业务对象运转。
第一层:为什么展位必须先是“活动资源”,再是客户记录
event.booth 的核心不是联系人字段,而是 event_id 和 state。
这说明 Odoo 先把展位看成活动资产,再允许它被某个客户占用。
源码里状态很克制,只有两个:
availableunavailable
很多人看到这里会觉得“是不是太简陋了”。 但恰恰因为状态简洁,展位对象才更适合作为主链路里的稳定锚点。
对活动团队来说,最重要的问题通常也就两个:
- 这个位子还能不能卖
- 这个位子现在归谁
如果一开始就把展位做成一张复杂 CRM 表,你很快会在以下场景里混乱:
- 场地位和客户意向混在一起
- 官网展示的展商与后台未成交客户混在一起
- 招商确认后,不知道该更新哪个对象
而 Odoo 的设计是:
- 先定义展位资源
- 再由客户占用资源
- 最后视配置决定是否派生出 sponsor / exhibitor 形象
这条顺序非常重要。
第二层:为什么展位上还要保存联系人快照
partner_id 之外,模型上还有:
contact_namecontact_emailcontact_phone
而且这些字段不是简单 related,而是 compute + store,并且“如果当前值为空,再从 partner 上补”。
这背后的产品判断很细:
res.partner负责长期客户主数据event.booth负责这次活动里的招商上下文
也就是说,Odoo 不希望你把展位完全绑死在客户主档上。
为什么?因为活动现场总会遇到这些情况:
- 签约主体是公司,但现场对接人是市场经理
- 同一家公司参加不同活动,对接邮箱和电话并不一样
- booth 已经确认,但客户主档还在清洗或合并
如果展位只保留一个 partner_id,这些业务细节就都要靠人脑记忆。
而 Odoo 让 booth 自带联系人快照,相当于把“这次活动里谁负责这个位子”固定下来。
这对招商运营特别重要,因为 booth 不是纯销售对象,它还面向:
- 物料通知
- 布展沟通
- 官网资料征集
- 现场协调
第三层:为什么确认展位时会发活动消息
create() 和 write() 很值得看。
- 新建后,如果 booth 已经不是 available,会立刻
_post_confirmation_message() - 后续如果从
available写成unavailable,也会触发_action_post_confirm()
这说明 Odoo 把“展位确认”看成活动级事件,而不是 booth 私有动作。
它不是只改一行状态,而是把确认结果通过 event_id.message_post_with_source(...) 发回活动消息流。
这套设计的价值在于:
1. 展位变化能进入活动协作上下文
运营、销售、项目经理不必各自维护私有台账。
2. 后台确认和前台确认能收敛到同一条业务语义
无论展位是后台手工确认,还是网站流程确认,最终都落到 booth 的确认动作。
3. 业务审计更清楚
后续追查“哪个 booth 什么时候被确认”,不会只剩下一次无意义的字段变更。
很多实施项目喜欢把这类动作留给人工发消息,但源码已经说明:
官方默认认为,展位确认本身就值得被记录成活动事件。
第四层:赞助商为什么不是手工再建一份,而是从展位派生
在 website_event_booth_exhibitor 扩展里,展位会多出一组 sponsor 相关字段:
use_sponsorsponsor_type_idsponsor_id- sponsor 的名称、邮箱、电话、标语、描述、Logo
更关键的是 _get_or_create_sponsor() 和 _action_post_confirm():
- 如果 booth 分类启用了 sponsor 逻辑
- 并且 booth 已有
partner_id - 确认展位时就会尝试查找已有 sponsor
- 找不到就自动创建一个新的
event.sponsor
而查找条件并不是只看 partner,还同时看:
partner_idsponsor_type_idexhibitor_typeevent_id
这几个条件组合起来非常有意思。
它表达的是:
同一家客户在不同活动、不同赞助层级、不同展商类型下,不应被粗暴当成同一个赞助对象。
这就避免了两个常见坑:
坑一:一个 sponsor 被多场活动串用
官网展示资料会串台,活动归属混乱。
坑二:同一家公司不同赞助层级被覆盖
明明一个活动里既有主赞助又有参展位,后台却只剩一条模糊档案。
所以 sponsor 不是“再建一份联系人”,而是 booth 确认后的活动传播对象。
第五层:为什么 sponsor 字段大量做成 related
扩展模型里你会看到很多 sponsor_* 字段本身是 related 到 sponsor_id。
这意味着官方明确区分了两类信息:
一类是 booth 自己持有的招商执行信息
比如:
- 当前租户是谁
- 当前 booth 是否已占用
- 本次活动联系人是谁
另一类是 sponsor 持有的官网传播信息
比如:
- sponsor 名称
- slogan
- 官网描述
- Logo
为什么要分层?
因为招商执行和市场展示的维护节奏并不一样。
- Booth 往往在销售确认、合同推进时变动
- Sponsor 档案往往在市场同事完善官网资料时变动
如果两套信息混在一个对象上,现场执行字段和官网展示字段就会彼此污染。 而 related 的做法让 booth 更像“入口”,sponsor 更像“展示主体”。
第六层:最值得实施顾问重视的业务边界
看完源码后,最该记住的是三个边界。
1. 展位可售状态,不等于客户是否成交
available / unavailable 只说明资源是否被占用,不自动等于合同、付款、发票全流程已完成。
所以实施时不要把 booth 状态硬改造成复杂销售漏斗。
2. Booth 联系人,不等于 sponsor 展示身份
前者偏执行,后者偏传播。两者相关,但不是一回事。
3. Sponsor 的生成,不应脱离 booth 主链路手工乱建
如果赞助商档案总是靠后台额外手输,最终一定会出现 booth 与官网信息不同步。
实战上该怎么用这套机制
如果你要把 Odoo Event Booth 用顺,推荐按这个思路落地:
- 先把 booth 当活动资源建完整,分类和层级先定好
- 用
partner_id + contact_*承接本次活动的实际对接人 - 以 booth 确认为分界点,再生成 sponsor / exhibitor 展示对象
- 官网展示、赞助物料、展商资料统一围绕 sponsor 维护
- 现场运营和招商管理继续围绕 booth 维护
这样你会得到两条既连接又不混乱的链:
- 招商执行链:展位 → 客户 → 联系人 → 状态 → 活动消息
- 官网传播链:展位确认 → sponsor 生成 → 官网资料 → 品牌曝光
最后一句话
event.booth 真正高明的地方,不是“能卖展位”,而是它把活动资源对象放在中间,再让客户关系和官网传播围绕它展开。
所以理解这张表的最好方式不是“摊位管理”,而是:
它是活动招商到展商展示之间的桥梁对象。
DISCUSSION
评论区