先说结论
Odoo 采购改交期,不是简单把采购行上的 date_planned 改掉。
源码真正做的是三件事一起发生:
- 在采购单上创建或累积一条
Date Updated活动; - 把新的日期写回对应采购行;
- 只把尚未完成的库存 move / deadline 往后同步,而不篡改已经完成的收货事实。
所以这套机制的核心思想不是“让日期保持一致”,而是:
在允许交期反复协商的前提下,尽量保住沟通痕迹和库存事实。
第一步:不是每改一行都新建一堆活动,而是优先复用同一条提醒
采购单上的 _update_date_planned_for_lines(updated_dates) 会先做一件很像协同软件的事情:
- 查找当前采购单、当前负责人、summary 为
Date Updated的mail.activity; - 找到就继续往里面追加 note;
- 找不到才创建新的活动。
这一步很聪明。
因为采购改交期往往不是一次性动作,而是:
- 供应商先说能延两天;
- 第二天又说部分物料再延三天;
- 采购员一次会改多行,甚至分几次改。
如果系统每次改一行都新建一条活动,负责人很快就会被消息淹没。
而 Odoo 的做法是:
把同一轮交期变更沉到一条可累积的 activity 里。
这既保住了可追溯性,也避免 chatter 失控。
第二步:activity note 记录的是“从什么时候改到什么时候”
_create_update_date_activity() 构建 note 时,会逐行记录:
- 产品名;
- 原始收货日期;
- 新收货日期。
_update_update_date_activity() 也沿用同样格式继续往 note 追加。
这意味着它不是只有一句“交期已更新”,而是明确保留:
- 谁的交期变了;
- 从哪天改到哪天。
对采购管理来说,这比单纯的字段历史更实用。
因为在真正沟通现场,负责人最关心的往往不是“字段是否变更”,而是:
- 哪些料延了;
- 延了多少;
- 是不是集中影响某一波收货。
第三步:采购行日期会改,但删除行和已确认状态有明显边界
采购单在 _update_order_line_info() 里既负责 catalog 场景的增改删,也会处理数量变更后的价格、seller 逻辑。
但真正和交期同步最相关的,是行级的 _update_date_planned()。
在 purchase_stock 里,这个方法不是盲改:
- 先找该采购行关联的
move_ids中,状态不在done/cancel的 move; - 如果没有任何已做 move,或存在可更新 move,才调用父类去改采购行日期;
- 如果有可更新 move,再把这些 move 的
date_deadline同步成新日期。
这背后有个很重要的现实假设:
已完成的收货是历史事实,不能因为采购员后来改了计划日期就被重新“洗白”。
所以 Odoo 只会推动未完成的执行对象往前/往后走,不会反写已完成 move 的历史完成时间。
第四步:为什么只同步未完成 move,是一个很好的设计边界
很多团队会抱怨:“我都把采购行日期改了,为什么某些收货记录没跟着一起改?”
答案正是:不该改。
如果一个入库 move 已经 done,那它代表的是:
- 实际货已经到了;
- 实际流程已经发生;
- 这条执行记录已经成为库存事实和分析依据。
这时再去追着把历史 deadline 改掉,会带来两个问题:
- 你会把“计划变更”误装成“历史本来如此”;
- 到货准时率、延期分析、供应商评估都会被污染。
所以采购改交期,本质上只能改未来,不能改过去。
这也是这条链路最值得称赞的地方:
它允许计划层更新,但拒绝篡改执行层既成事实。
第五步:它不是完整的供应商协同平台,但已经把最关键的可追溯性留住了
别把这条链路想得太大。
它并不会自动:
- 给供应商发一封确认函;
- 校验改期是否违反采购协议;
- 自动重新排产或重排下游工单;
- 替你判断延期是否需要拆单、改路线或改仓。
但它已经做了很关键的三件基础工作:
- 记录改期;
- 汇总改期;
- 同步未完成执行对象。
这就给后续更复杂的协同、审批、预警留出了稳定基座。
最容易误解的 4 个点
1. 以为改交期只是字段 write
错。它会先处理 activity,再处理行,再处理未完成 move 的 deadline。
2. 以为每改一次都会新建一条活动
不一定。系统优先复用同一张 PO 上已有的 Date Updated 活动并追加 note。
3. 以为已完成收货也会被同步改日期
不会。已完成 move 的事实时间不该被追改。
4. 以为采购行日期和库存执行日期永远严格一致
不是。Odoo 保证的是“未来待执行对象尽量跟计划同步”,不是把所有历史对象强行刷成同一天。
实战排错顺序
如果用户说“我改了采购日期,但界面感觉没全改”,建议按这个顺序查:
- 先看 activity 有没有生成或复用;
- 确认你改的是采购行还是通过 catalog 更新行;
- 检查相关 move 是否已经
done/cancel; - 看被同步的是
date_deadline还是你期待的别的字段; - 确认当前 PO 负责人是谁,activity 是不是记到了对应 user。
一句话记忆法
Odoo 采购改交期的重点不是“把所有日期刷一致”,而是“把未来计划往后推,同时保住已经发生的收货历史”。
DISCUSSION
评论区