其他深度

Odoo 午餐提醒为什么不只是“发个通知”:定时任务、收件人圈选与地点定向链路讲透

很多人只注意 Odoo Lunch 的下单逻辑,却忽略了 lunch.alert 才是真正连接运营节奏和员工触达的那层能力。源码里它把时区换算、动态 cron、订餐地点过滤、最近下单人群筛选和消息投递收成了一条精细化提醒链。

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

先说结论

Odoo Lunch 的提醒系统,不是一个“到点群发一句话”的小功能。

/home/ubuntu/odoo-temp/addons/lunch/models/lunch_alert.py 来看,lunch.alert 实际上把下面几层能力揉到了一起:

  • 根据提醒配置动态生成和维护 ir.cron
  • 按时区把“上午 10 点”换算成真正的执行时间
  • 根据星期与截止日期判断今天要不要展示或发送
  • 按地点过滤目标用户
  • 按最近一周 / 一月 / 一年是否点过餐圈选人群
  • 通过消息系统把提醒发给对应员工

所以它真正解决的问题不是“如何发提醒”,而是:

公司午餐提醒怎样在正确时间、发给正确的人、并且跟着地点和历史订餐习惯自动收缩范围。

第一层:为什么提醒记录要自带一个 cron

lunch.alert 里最值得注意的字段之一是 cron_id

也就是说,每一条提醒配置,不是共享一个统一大任务,而是直接绑定自己的一条 ir.cron

这说明 Odoo 不把午餐提醒看成“每天固定广播”的单一动作,而是允许每条提醒拥有自己的节奏、时区和生命周期。

这很重要,因为真实办公场景里常常会有多种提醒同时存在:

  • 总部每周五的餐补提醒
  • 某个办公点临时供应商变更通知
  • 节假日前的特殊订餐说明
  • 只想提醒最近确实有点过餐的人

如果所有提醒都塞进一个通用 cron,再在代码里硬分支,很快就会变乱。

Odoo 选择“每条提醒一条 cron”,相当于让每个提醒成为一个可独立调度的对象。

第二层:为什么时区要作为提醒模型的一部分

提醒里有这些字段:

  • notification_time
  • notification_moment
  • tz

_sync_cron() 会用提醒自身的时区,把“上午几点”本地化后再转成 UTC 写进 cron.nextcall

这背后的设计非常成熟。

因为午餐提醒是典型的与本地生活节奏强绑定的通知:

  • 对上海办公室来说,10:30 是订餐提醒
  • 对巴黎办公室来说,同样写 10:30,绝不能变成北京时间 10:30 执行

如果时区只放在用户侧,而不是提醒规则侧,管理员配置全局提醒时会非常容易出错。

Odoo 把时区作为提醒对象自己的属性,等于在说:

提醒不是抽象事件,而是一个发生在具体本地时间的运营动作。

第三层:为什么 cron 要动态启停,而不是一直跑

_sync_cron() 里会根据当前提醒状态判断 cron_required,只有满足这些条件才真正启用:

  • active = True
  • mode = chat
  • 还没超过 until

否则 cron 就会被关闭。

这说明 Odoo 的思路不是“让所有 cron 一直跑,再在执行时决定要不要跳过”,而是尽量让无效任务根本不进入调度

这有两个现实好处:

1. 降低后台噪音

已经过期的提醒、不再发送聊天通知的提醒,不会继续占调度资源。

2. 让提醒配置和执行状态更一致

运维人员看到 alert 是 inactive 或过期时,背后的 cron 也同步失效,不会出现“界面关了,任务还在跑”的错觉。

第四层:为什么系统要判断“今天是否可用”

available_today 的计算取决于两类条件:

  • 星期几开关(monsun
  • until 是否已经过去

这说明 Odoo 把午餐提醒理解成一种带日历条件的运营规则,而不是一条裸消息。

这非常贴合场景。

因为午餐提醒经常不是长期每天都一样:

  • 只在工作日有效
  • 某个短期促销活动只做到月底
  • 某供应商周三不开门

所以“今天该不该提醒”必须先于“现在要不要发送”。

否则你会得到大量形式上按时、实际上不该出现的通知。

第五层:为什么收件人不是所有员工,而是按历史行为筛选

recipients 支持:

  • everyone
  • last_week
  • last_month
  • last_year

_notify_chat() 会通过 lunch.order 去找近一段时间有订餐记录、且未取消的用户,再拿到对应 partner 发通知。

这说明 Odoo 对午餐提醒的理解,已经不是“公司公告”,而是轻量运营触达

这个区别很关键。

因为午餐这种场景里,最怕的是:

  • 全员广播太多
  • 从来不点午餐的人也被反复骚扰
  • 提醒成本越来越高,打开率越来越低

而按最近一周 / 一月 / 一年点过餐的人来筛选,就能大致圈住:

  • 活跃用户
  • 潜在回流用户
  • 长期沉睡但曾经有需求的人

这是很典型的产品运营思维,不再是简单 OA 通知思维。

第六层:为什么地点过滤要放进提醒域里

如果提醒配置了 location_ids,系统会把目标用户进一步限定为:

  • user_id.last_lunch_location_id 在这些地点内

这个逻辑非常实用。

因为办公室午餐往往不是一个全国统一场景,而是高度依赖地点:

  • 不同楼层、园区、城市供应商不同
  • 配送范围不同
  • 订餐截止时间可能不同

如果没有地点过滤,总部通知很容易打到分部,A 楼活动也会发给 B 楼员工。

Odoo 选择用“用户最近午餐地点”做过滤,虽然不是绝对完美,但非常接近实际可用。

它不是去维护一套过重的静态组织树,而是用午餐行为本身来推断提醒相关性。

第七层:为什么提醒最终走消息系统,而不是另造一套发送器

_notify_chat() 最后调用的是 mail.thread.message_notify()

这代表 Lunch 并没有自己发明一套独立的通知引擎,而是复用 Odoo 现有消息体系。

好处很明显:

  • 权限和消息基础设施一致
  • 通知留痕更统一
  • 后续若扩展到其他消息入口,复用成本更低

这类设计很符合 Odoo 一贯风格:

  • 业务模块负责决定“通知谁、何时通知、为何通知”
  • 底层消息框架负责“怎样送达”

模块边界因此更清楚。

最容易误解的四个点

误区一:Lunch Alert 只是提醒文案配置

不对。它实际上还承担了调度、时区换算、目标筛选和生命周期管理。

误区二:午餐提醒应该默认全员发送

源码显然不是这么想的,它支持按历史订餐行为缩小人群。

误区三:地点只是前端展示信息

其实地点会直接影响提醒命中的用户范围。

误区四:提醒过期了只是不再显示

不只是显示层,背后的 cron 也会随之停掉甚至删除。

实战上怎么把 Lunch 提醒做得更有效

如果你在实施 Odoo Lunch,我建议:

  1. 不要一上来就做全员广播,优先从活跃订餐人群开始
  2. 多地点办公场景下,把地点维度的提醒拆开配置
  3. 管理员创建提醒时,要明确按哪一个办公室时区生效
  4. 临时活动型提醒记得设置 until,让它自己退出调度
  5. 把提醒文案、供应商截止时间和下单入口一起设计,不要只发一句“快订餐”

最后总结

Odoo Lunch 的提醒机制,最有价值的地方不是“能定时发消息”,而是它把午餐运营里真正关键的三件事组合了起来:

  • 正确时间
  • 正确地点
  • 正确人群

再加上动态 cron 与消息框架复用,这就让 lunch.alert 从一个小配置项,变成了一套足够精细的内部服务触达工具。

所以真正理解它,不是把它看成“通知模板”,而是看成:

围绕午餐场景做轻量精细化运营的一台调度器。

DISCUSSION

评论区

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