其他深度

Odoo 午餐为什么不只是“下个外卖单”:合单、钱包余额、加料约束与订餐截止时间链路讲透

Odoo Lunch 看起来轻量,但源码里其实塞进了不少运营细节:同款订单自动合并、余额不足不让继续加、供应商截止时间控制、配料数量校验,全都在守一件事——让公司内部订餐既顺手又不失控。

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

先说结论

Odoo Lunch 不是一个“把菜单搬到系统里”的小工具,而是一套专门面向公司内部集体订餐的轻运营模型。

/home/ubuntu/odoo-temp/addons/lunch/models/lunch_order.py 看,lunch.order 关注的不只是“你点了什么”,还同时管:

  • 当天能不能订
  • 供应商今天接不接单
  • 是否过了截止时间
  • 同一个人的相同订单要不要合并
  • 钱包余额够不够
  • 配料选择是否满足规则

所以它真正解决的问题不是点餐动作本身,而是:

公司里很多人每天都在下单,系统怎样既让流程顺滑,又避免订单碎片化和财务失控。


第一层:为什么午餐订单不是“每点一次就新建一条”

create() 里最有意思的逻辑之一,就是 _find_matching_lines()

当用户新建订单时,系统会先查:

  • 同一个用户
  • 同一个产品
  • 同一天
  • 同样备注
  • 同样取餐地点
  • 同样状态
  • 同样配料组合

如果找到匹配行,不是继续新建,而是:

  • 直接 update_quantity(1)
  • 把数量加到已有订单上

这说明 Lunch 的核心目标之一,是减少碎片订单

为什么这很重要? 因为内部订餐和普通电商不同:

  • 同一个人可能反复改数量
  • 同一办公室大量订单需要统一汇总给供应商
  • 后台更关心“最终要送几份”,而不是“按钮被点了几次”

所以 Odoo 默认把重复下单理解成数量变更,而不是新增业务对象。


第二层:为什么编辑订单时也会尝试再合并

write() 里还有一层更细的处理。

当这些信息变化时:

  • 备注
  • 配料
  • 状态
  • 用户
  • 产品
  • 取餐地点

系统会再次尝试找匹配订单,把相同内容的订单合并,并把旧行 active=False 处理掉。

这很能体现 Lunch 的产品思路:

  • 用户看到的是“我在改我的午餐”
  • 系统内部维护的是“最终汇总后应发给供应商的订单结构”

因此 Lunch 不是把每次界面操作都当成不可变历史,而是更重视最终汇总结果。

这和采购、销售那种强调订单原子性的模型很不一样。


第三层:钱包余额为什么会影响“还能不能继续点”

_compute_display_add_button() 里,系统会先统计:

  • 这个用户当天所有 new 状态订单
  • 它们累计多少钱
  • 再去调用 lunch.cashmove 算钱包余额

最后只有在余额覆盖当前订单价格时,才显示继续添加按钮。

这说明 Lunch 的“余额控制”不是结算时最后拦一次,而是在用户持续点单的过程中就介入。

这样做有两个好处:

1. 减少无效下单

用户一开始就知道自己还能不能加,而不是最后统一报错。

2. 保证内部补贴或预充值规则可执行

很多公司午餐系统不是实时付款,而是预存或公司补贴余额机制。 如果前面不控,后面会很难对账。

所以 Lunch 在这里其实已经开始碰内部财务边界了。


第四层:为什么截止时间和可订日期是订单级判断

Lunch 里同时有两类时间边界:

  • available_on_date
  • order_deadline_passed

逻辑大致是:

  • 供应商今天是否营业
  • 指定日期是否能订
  • 如果就是今天,当前时间是否已经过了供应商截止时间

很多人会觉得这个判断应该挂在供应商上就够了。 但 Odoo 放在订单级计算,原因很实际:

  • 同一个供应商,不同订单日期结果不同
  • 同一个用户今天能不能订,和明天能不能订,不是同一个问题
  • 界面渲染时需要直接判断当前订单状态

也就是说,供应商定义的是规则,订单承担的是规则在本次订餐上的结果


第五层:配料选择为什么要做严格约束

Lunch 不是简单地让你勾几个加料选项。

在模型里,配料被拆成:

  • topping_ids_1
  • topping_ids_2
  • topping_ids_3

并且每组都可能有不同数量要求,比如:

  • 必选一个
  • 至少选一个
  • 可以不选

_check_topping_quantity() 会按供应商规则校验这些约束。

这说明 Odoo 的 Lunch 不是把加料当成自由文本,而是在试图标准化餐品配置。

这样做的价值在于:

  • 订单更容易汇总
  • 供应商收到的信息更规范
  • 价格与配置更容易对应
  • 用户少犯“忘选必选项”的错误

第六层:为什么 Lunch 仍然保留状态机

state 包含:

  • new
  • ordered
  • sent
  • confirmed
  • cancelled

这说明 Lunch 虽然轻量,但它并不只是个人收藏夹式购物车。

它仍然是一条有内部处理过程的链:

  • 用户先选餐
  • 内部确认并汇总
  • 再发给供应商
  • 最后确认收到

这对于办公室统一订餐非常合理。

因为真正难的不是“某个人点了什么”,而是:

  • 什么时候汇总
  • 谁发给供应商
  • 供应商是否接单
  • 实际是否收到了餐

所以状态机虽然简单,但很必要。


最容易误解的三个点

误区一:Lunch 就是个小商城

不是。它更像一个内部订餐调度系统,重点在汇总、余额和规则控制。

误区二:订单合并是可有可无的小优化

其实非常关键。没有合并,内部订餐在高频场景下会迅速碎成很多重复小单。

误区三:余额校验只是页面提示

也不是。它和 cashmove 绑定,背后直接关系到公司补贴或预付金规则是否能落地。


实战上最该关注什么

如果你想把 Lunch 用得顺,最重要的是先配好三类规则:

  1. 供应商规则:营业日、截止时间、加料标签、加料数量限制
  2. 资金规则:钱包充值、公司补贴、余额不足时的处理方式
  3. 汇总规则:谁来把 new/ordered/sent 这些状态推进下去

当这三层跑顺后,Lunch 的体验会非常像一个“低摩擦但强约束”的公司内部服务。


最后一句

Odoo Lunch 看似轻,但它很懂办公室订餐真正的麻烦在哪里:

  • 同一人会反复改单
  • 供应商有截止时间
  • 配料规则容易出错
  • 公司还要控制余额和补贴

所以它不是在做一个外卖 App,而是在做一套适合组织内部运转的订餐机制

DISCUSSION

评论区

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