预计到货

Odoo 采购“预计到货”为什么总被误读:订单日期、行日期与最早到货规则讲透

很多人把采购单上的 Expected Arrival 当成“整单统一到货时间”,但源码里它其实是所有采购行 date_planned 的最早值,而且订单与行之间还存在双向影响。本文把这个边界讲透。

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

先说结论

Odoo 采购单上的 Expected Arrival,并不是“整张 PO 的统一承诺日期”。

/home/ubuntu/odoo-temp/addons/purchase/models/purchase_order.py 里,订单级 date_planned 的计算规则非常直接:

取所有非展示行 order_line.date_planned 的最小值。

也就是说,采购单头上的预计到货,本质上是:

  • 整单里最早要到的一行
  • 不是最晚
  • 不是平均
  • 更不是“用户脑海里这张单的主日期”

这就是为什么一张多行 PO 里,只要有一行交期更早,单头日期就会被拉到更早的那个时间点。


核心链路:订单头不是主数据,采购行才是主语义

源码里有两条很关键的逻辑:

  1. purchase.order._compute_date_planned():单头取最早行日期
  2. purchase.order.onchange_date_planned():如果你手动改单头,会把日期写回所有非展示行

这说明 Odoo 对 date_planned 的态度很明确:

  • 真实业务语义在行上
  • 单头只是一个方便查看和整体编辑的聚合入口

这跟很多实施人员的直觉正好相反。

很多人会把采购单头当成“主日期”,然后默认各行自动继承;而源码的真实世界更像是:

  • 各行有自己的计划到货时间
  • 单头只是把最早那个提炼出来给你看

为什么新建采购行时,日期会看起来“自动算好了”

purchase_order_line.py 里,_get_date_planned() 的逻辑很简单:

  • 如果 PO 有 date_order
  • 就用 date_order + seller.delay
  • 如果没有 date_order
  • 就用当前时间 + 供应商 delay

所以采购行默认日期不是凭空出现,而是建立在:

  • 下单日期
  • 供应商交期 delay

这条链路之上。

于是很多现场问题的根因也就很清晰了:

  • 不是系统瞎写了计划日期
  • 而是你改了供应商、采购单位、选中的 seller,导致行级默认日期重新推导

最容易被忽略的一点:改单头和改行,语义完全不同

改单头日期

onchange_date_planned() 会把单头日期同步给全部非展示行。

这更像一种“批量覆盖”。

改某一行日期

订单重新计算后,单头会变成所有行里最早的那个。

这更像“局部变化影响聚合结果”。

所以很多用户会觉得 Odoo 的日期“来回跳”,其实它只是同时支持了:

  • 自上而下的批量覆盖
  • 自下而上的最早值聚合

如果脑子里没有这两层模型,就会觉得它反直觉。


为什么源码还专门写了一个 onchange 覆盖保护

purchase.order.onchange() 里有一段很关键的保护逻辑:

  • 当 PO 行变化导致单头 date_planned 跟着变时
  • 不要反过来把所有行又重写一遍

这段代码的存在,本身就说明 Odoo 开发者也知道这个场景很容易出现“递归污染”:

  • 行更新了
  • 单头变了
  • 单头再回写行
  • 行再触发单头变化

如果不做保护,用户改一行交期,可能会意外污染整张单的所有行日期。

所以这不是多余代码,而是在守住“聚合字段”和“批量编辑入口”之间的边界。


供应商通过门户更新交期,为什么不是只改单头

在同一个文件里还能看到:

  • get_update_url()
  • _update_date_planned_for_lines()
  • get_localized_date_planned()

这说明 Odoo 甚至考虑了供应商或外部用户通过门户去更新计划日期的场景。

而且更新的核心对象仍然是:

  • 具体采购行
  • 然后系统再记录 activity,并让订单级日期重新聚合

这再次证明:

Odoo 真正认定的“交期事实”,在采购行,不在单头。


业务误区:把单头日期当成承诺日期总开关

很多团队会这么用:

  • 改了单头日期,就以为整张单的所有收货、提醒、延期判断都会自然准确

这在单行 PO 时问题不大;但在多行、多品类、多供应商包装条件不同的采购单里,风险很大。

因为真实情况可能是:

  • A 行三天到
  • B 行十天到
  • 单头显示三天

如果团队把这个字段当“整单都会三天到”,后面的催货、承诺、仓库排班都可能被带偏。


排错顺序应该怎么走

如果你遇到“为什么预计到货不对”,建议按这个顺序查:

  1. 先看单头 date_planned 是不是被手工改过
  2. 逐行看 order_line.date_planned 哪一行最早
  3. 确认行级 selected_seller_idseller.delay 是否变化
  4. 看是不是改了供应商、单位、数量后触发了行级重算
  5. 如果是门户更新场景,确认实际被更新的是哪些行
  6. 再回头评估提醒邮件、late 状态是不是基于最早日期在工作

对实施和二开的提醒

如果业务真的需要“整单承诺到货日”,最好单独建一个字段,不要直接把 Odoo 的 date_planned 当它用。

因为源码语义已经很明确:

  • 它是采购行交期的聚合视图
  • 聚合规则还是“最早值”

你硬把它当“整单承诺日期”,就会在多行采购里不断碰壁。


一句话记忆法

Odoo 采购单头的 Expected Arrival 不是整单统一到货承诺,而是所有采购行计划日期里的最早值。

DISCUSSION

评论区

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