关班边界

Odoo POS 挂单为什么有的会拦关店、有的却能留到明天:draft order、preset time 与 close session 边界讲透

很多人以为 POS 关店只看有没有未支付单,但 point_of_sale 实际把今天的 draft 单、未来预订单、取消权限和关班弹窗提示拆成了两套边界。

POS
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 4 阅读

先说结论

Odoo POS 的“关班前不能有挂单”并不是一句粗暴规则。

源码实际上把两类 draft 单分开处理:

  1. 今天就该处理的 draft 单,会直接阻止关班;
  2. 未来日期的预订单,可以脱离当前 session 留到后面再处理。

所以它的本质不是“有 draft 就一刀切”,而是:

按订单的时间语义,决定它到底属于当前收银班次,还是属于未来业务。

一、为什么 _check_if_no_draft_orders() 看起来严格得近乎不讲理

pos_session.py 里的 _check_if_no_draft_orders() 很直接:

  • 找出 session 内 state = draft 的订单;
  • 只要还有,就不允许验证 session;
  • 还会把订单名列出来,要求收银员先支付或取消。

如果只看这段代码,你会觉得 Odoo 很死板:

  • draft 就是不行,没得商量。

但问题是,这段逻辑保护的是:

  • 当前班次资金、订单、库存与会计闭环。

只要“属于今天这一班”的草稿单还没落地,它就意味着:

  • 订单责任尚未结束;
  • 付款状态不完整;
  • 后续关班数据可能不干净。

所以这条规则不是针对“草稿单很烦”,而是针对:

  • 别把一个还没结清的当前班次事务硬塞进已关闭班次。

二、为什么 future preset order 又能例外

关键例外在 action_pos_order_cancel()

这个方法会把 draft 单分成两组:

  • today_orders:没有 preset_time 或时间不晚于今天;
  • next_days_orderspreset_time 落在未来日期,且仍是 draft。

然后处理方式完全不同:

  • today_orders 直接写成 cancel
  • next_days_orders 则把 session_id = False,从当前 session 脱开。

这说明 Odoo 对未来预订单的理解,不是“未完成的当前挂单”,而是:

  • 本来就属于未来业务时间窗的草稿订单。

既然它本来就不应该计入今天这班的结算闭环,那么在关班前把它从当前 session 脱离,就是合理的。

三、为什么未来预订单不能直接取消

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

  • 如果选中的订单 preset_time.date() > today,会抛错:不能取消未来的 delivery / pickup 订单。

这很有代表性。

Odoo 不希望收银员在关班压力下,顺手把未来预订单当普通挂单清掉。

因为从业务上看,这些订单常常代表:

  • 预约取餐;
  • 未来配送;
  • 按时制作的餐饮订单;
  • 需要保留的承诺。

所以系统给它的处理不是“取消”,而是“脱离当前班次”。

四、前端 closing popup 为什么也要展示 next days 信息

closing_popup.js 里有个 orderForNextDays 计算:

  • 统计 preset_time > now 且 state = draft 且有行的订单数量。

这说明前端关班弹窗不是只展示收银金额,它也在提醒操作者:

  • 当前还有多少未来订单挂在系统里。

这一步的价值在于让收银员心里有数:

  • 有些订单不是漏处理;
  • 它们是未来订单,应该按未来业务继续存在。

也就是说,弹窗承担的不是纯粹会计确认,而是:

  • 帮助人区分“必须清理的今天挂单”和“应保留的未来订单”。

五、为什么这套边界很适合餐饮和预约场景

如果所有 draft 单都必须当场支付或取消,很多带预定能力的 POS 就会很难用。

例如:

  • 餐厅今天晚上为明天下午接的预订;
  • 门店今晚录入了明天自提的订单;
  • 预约型业务允许先占坑、后结账。

这些单据的共同点是:

  • 它们确实是 draft;
  • 但它们不属于当前收银会话的结算责任。

Odoo 用 preset_time 把这类订单从“今日挂单”里切出来,本质上是在给 POS 加一层时间维度。

六、最容易误解的几个点

误解 1:关班前只要有 draft 单就说明出错了

不对。未来预订单可能是正常业务结果。

误解 2:未来预订单就应该直接取消

不对。源码明确禁止把未来配送/自提订单当普通挂单清掉。

误解 3:session closing 只关心钱

不对。它也关心哪些订单在业务上属于当前班次。

误解 4:前端弹窗只是展示金额

不对。它也在帮助区分 today draft 与 next-day draft。

七、做定制时最该保留什么

如果你要改 POS 关班逻辑,最值得保留的是:

  1. 今天挂单与未来预订单分层处理;
  2. 未来订单优先脱离 session,而不是粗暴取消;
  3. 关班 UI 里继续把这两类订单区分给操作者看。

否则你很容易把“时间上合理存在的未完成订单”和“真正该清掉的挂单”混为一谈。

最后一句

理解 Odoo POS 的关班边界,重点不是“draft 单能不能存在”,而是看懂这条主链:

当前 session draft 单阻止关班 → future preset draft 单脱离 session → closing popup 把两类语义显式区分。

看懂以后你就会知道,Odoo 不是在容忍未完成订单,而是在按时间归属给它们分班。

DISCUSSION

评论区

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