协同办公

Odoo 周期会议为什么不是“复制多条记录”:recurrence、例外事件、参会人状态与视频会议链路讲透

Odoo 的周期会议并不是简单批量复制日程。官方源码显示,它真正维护的是 recurrence 规则、例外事件、参会人状态重置、提醒重建,甚至还会把视频会议频道和后续事件关联起来。

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

先说结论

很多人看到 Odoo 的周期会议,会下意识理解成:

  • 把一条会议复制很多份
  • 以后分别改就行

这只是表面。

addons/calendar/models/calendar_event.py 看,Odoo 真正在维护的是:

  • 一条 calendar.recurrence 规则
  • 一组跟随这条规则的事件
  • 一批脱离规则的例外事件
  • partner_ids 对应的 attendee_ids
  • 会议提醒的重建
  • 必要时共享的视频会议频道

一句话说:

Odoo 的周期会议不是“复制卡片”,而是“规则 + 实例 + 例外 + 通知同步”的协同模型。


为什么 calendar.event 里同时有 partner_idsattendee_ids

这点很容易让人疑惑。

源码里既有:

  • partner_ids:参会人集合
  • attendee_ids:参会状态对象

为什么不只保留一个?

因为“谁被邀请了”和“这个人是否接受 / 拒绝 / 待确认”不是同一层信息。

Odoo 的做法是:

  • partner_ids 表达名单
  • attendee_ids 表达名单上每个人的响应状态

在 create / write 里,只要 partner_ids 改了,系统就会通过 _attendees_values() 自动生成或重建 attendee_ids

这意味着:

参会人名单是静态集合,attendee 才是协同状态。


周期会议为什么不是简单复制

源码里,周期会议的核心字段有:

  • recurrency
  • recurrence_id
  • follow_recurrence
  • recurrence_update

这些字段一起说明:

  • 一条会议是否进入周期模式
  • 它跟随哪条 recurrence 规则
  • 当前这条是否仍然“跟着规则走”
  • 修改时到底影响“这一次 / 之后的 / 全部”

如果只是简单复制,根本不需要这些语义层。

Odoo 明显想保留的是更高级的操作:

  • 改这一场
  • 改这一场及之后
  • 改整个系列

这跟真正办公日历里的用户心智是一致的。


为什么会有 follow_recurrence

follow_recurrence 很值得注意。

它表示当前事件是不是还继续服从原来的周期规则。

一旦你对某一场会议做了足够“局部化”的修改,比如单独改时间,源码就可能把它从原规则里剥离,让它变成例外事件。

这就是为什么你会看到:

  • 周期系列还在
  • 但某一场已经不再完全跟着系列走

这不是 bug,而是官方明确支持的“例外事件”机制。


为什么修改周期会议时会出现 “This event / future events / all events”

这不是纯前端文案,而是后端模型真的按这三种语义处理。

write() 里,Odoo 会根据 recurrence_update 判断:

  • self_only
  • future_events
  • all_events

然后走不同链路:

改这一场

保留整个系列,只把当前事件局部剥离出来。

改这场及之后

通过 _update_future_events()

  • 先把后续事件从旧 recurrence 裁开
  • 当前事件更新为新起点
  • 再生成一套新的 recurrence 规则

改整个系列

通过 _rewrite_recurrence()

  • 归档旧系列
  • 以 base event 为基础重写 recurrence
  • 重新生成整套后续事件

所以这套行为绝不是“多条记录一起 update 一下”。

它是对时间序列规则的重写。


为什么参会人状态会被重置

源码里 _reset_attendees_status() 很说明问题。

当时间类字段变化时,Odoo 会把:

  • 当前用户的 attendee 设为 accepted
  • 其他人的状态重置为 needsAction

这背后的协同逻辑很合理:

会议时间被改了,别人之前的接受,不应自动等同于“仍然接受新时间”。

这点如果不做,日历系统就会在最关键的地方失真。

所以 Odoo 不是只改会议日期,还会改参与者对这次邀请的有效状态。


为什么提醒也要重建

write() 里只要涉及:

  • partner_ids
  • 时间字段
  • alarm_ids

就会触发提醒相关重建。

这是因为会议提醒不是一个孤立功能,它依赖:

  • 谁参加
  • 什么时候开
  • 周期规则是否变化

一旦这些条件改变,旧提醒的触发时间可能已经失效了。

所以官方实现会:

  • 重新 setup alarms
  • 对 recurrence 场景按系列维护下一次提醒

这说明在 Odoo 看来,日历不是“把会开出来”,而是“确保会前通知链条也成立”。


为什么周期会议的视频会议链接也不是随便复制

源码里还有一个很容易被忽略的点:

  • videocall_location
  • videocall_channel_id
  • access_token

尤其 _set_discuss_videocall_location() 注释写得很清楚:

  • 周期事件的各次会议会有不同 access_token
  • 这是有意为之,避免 base event 删除后导致无法进入视频会议

同时,_create_videocall_channel() 又会在 recurrence 场景下,让同一系列的事件共享或继承视频频道。

这说明 Odoo 在做的是一种平衡:

  • 链接 token 不完全复用,避免脆弱依赖
  • 频道语义又尽量保持系列一致

这比“复制一个会议链接到所有记录”成熟得多。


为什么私密会议只显示 Busy

calendar.event 还继承了 mail.thread,所以它天然带有消息和协同属性。

但 Odoo 同时又做了隐私控制:

  • 对非参与者的 private event,名称等敏感字段会被替换成 Busy

这说明 Calendar 在官方设计里,不只是排程工具,也是一个需要做权限切面的协同空间。

换句话说:

  • 你可以知道别人忙不忙
  • 但未必能知道别人忙什么

这正是企业日历很重要的边界。


做周期会议定制时最容易踩的坑

1. 把 recurrence 当成“批量复制模板”

结果一到“未来事件”修改就逻辑崩掉。

2. 只改 partner_ids,不理解 attendee_ids

结果参会状态、邮件通知和 RSVP 语义都不对。

3. 时间改了却不重置 attendee 状态

别人会被系统错误地视为已经接受新会议时间。

4. 忽略 alarm 重建

提醒时间会漂。

5. 视频会议链接简单复用

系列被拆分或删除后,容易留下脆弱引用。


一句话记忆法

Odoo 的周期会议不是“复制多条日程”,而是用 recurrence 规则去管理一串事件,并允许在中途拆出例外、重置参会状态、重建提醒和维护视频会议链路。

理解这一句,Calendar 的很多“为什么它这样改”都会变得很顺。

DISCUSSION

评论区

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