很多实施现场都会碰到一种抱怨:
- 系统昨天还说下周采购
- 今天又说最好明天就下
- 明明供应商提前期没改,建议日期却还是在跳
于是大家很容易下结论:
Odoo 的补货日期算法不稳定。
但如果沿着 /home/ubuntu/odoo-temp/addons/stock/models/stock_rule.py、stock_orderpoint.py、stock_move.py 这几条链去看,会发现它其实不是在“正推什么时候到货”,而是在做另一件事:
从需要满足的日期开始,沿着各类 lead time 一层层往前倒推,算出最晚应该何时触发补货。
一旦你把它理解成“倒排”,很多看起来反直觉的结果就会正常起来。
一、补货日期的起点,不是今天,而是“需求日期”
Odoo 不会先问“今天适不适合买”,它先问的是:
- 这批货最晚什么时候必须到位?
这个日期可能来自:
- 销售单承诺交期
- 下游库存移动的计划日期
- 订单点(orderpoint)自己的补货计算时点
- MTO 需求链向上游传来的
date_planned
所以补货逻辑的第一步不是算采购,而是先拿到目标满足日期。
二、stock.rule 的 delay 不是供应商天数,而是“本规则这一步要提前多少天”
在 stock_rule.py 里,规则本身就有 delay 字段。
这个字段经常被误会成“供应商交期”。其实更准确的理解是:
- 当需求经过这条规则时,这一跳要往前挪多少天
也就是说,它属于“规则层 lead time”,不是供应商层 lead time。
如果一条链路经过多条规则,系统会把这些时间逐层向前折算。
所以你看到建议日期提前,不一定是 vendor lead time 改了,也可能是:
- 路由换了
- 规则变了
- 仓库步骤增加了
- 某一跳开始计 lead time 了
三、供应商提前期管的是采购这一步,而不是整条链的全部时间
当流程落到 buy rule、供应商信息等采购语境时,供应商提前期才真正开始发挥作用。
它回答的问题是:
- 从下采购动作到货物可收,需要留几天
这和 stock.rule.delay 是不同层级:
stock.rule.delay:链路某一跳的规则提前量supplier lead time:采购这一步供应商履约提前量
很多团队把这两个量混成一个,所以一旦采购建议日期变化,就只盯着供应商资料看,结果总觉得系统“算错了”。
实际上,系统可能只是把其他链路时间也纳入了倒排。
四、visibility_days 改的不是到货日,而是“系统多早开始看见缺口”
visibility_days 特别容易被误读。
它不是在修改货物真正的计划到货时间,而是在改变补货算法的观察窗口。
更直白地说:
- 没有 visibility days 时,系统更接近“缺口快到了再触发”
- 有 visibility days 时,系统会提前几天就把未来缺口纳入补货考虑
所以它改变的是:
你何时开始行动,而不是需求本身发生在什么时候。
这也是为什么同样的需求、同样的供应商提前期,仅仅调大 visibility_days,采购建议就会前移。
不是交货变慢了,而是系统更早提醒你了。
五、MTO 场景里,日期会沿需求链继续向上游传
在 stock_move.py 里,和 MTO 相关的方法会继续把 date_planned 向上游传播。
这意味着一张销售单的需求日期,可能不是停在出库拣货,而是一路影响到:
- 上游补货 move
- 采购建议
- 制造建议
所以在 MTO 或混合补货链里,最终采购日期往往不是“采购模块独立算出来的”,而是整条需求链倒排后的结果。
这也解释了一个常见现象:
- 同一个产品
- 手工补货建议日期是一套
- 从销售触发的自动补货日期又是一套
因为两者的需求起点和传播路径根本不一样。
六、为什么日期会“今天看”和“明天看”不一样
很多人一看到建议日期变化,就怀疑计划器不稳定。其实常见原因有这些:
1. 需求起点变了
比如销售交期改了、下游 move 日期重算了、订单点覆盖范围变了。
2. 观察窗口变了
visibility_days 会让未来缺口更早进入视野。
3. 规则链变了
多步仓、不同 route、不同 warehouse 设置,都会改变倒排路径。
4. 上游来源不同
手动补货、orderpoint、销售触发、MTO 触发,本来就不是完全同一条日期链。
所以“今天和明天不一样”不一定是 bug,很多时候只是输入边界变了。
七、实施里最容易踩的坑
坑 1:把所有提前期都当成 vendor lead time
结果看到日期前移,就只去改供应商资料,越改越乱。
坑 2:把 visibility_days 当成库存安全量
它不是数量缓冲,而是时间上的前视窗口。
坑 3:忽略 route / rule 层的 lead time
尤其多步仓、跨仓补货、MTO 链路里,这一层影响非常大。
坑 4:拿不同触发路径的结果直接比较
orderpoint 看到的建议日期,不必然等于销售单触发出来的采购日期。
八、一个更好用的排错顺序
如果你想搞清楚“为什么系统建议这一天采购”,建议按这个顺序查:
- 最终要满足的需求日期是什么
- 这条需求走的是哪条 route / rule
- 每一跳规则有没有
delay - 采购这一步选中了哪个 supplier lead time
- orderpoint 有没有设置
visibility_days - 这是手动补货、orderpoint 还是销售/MTO 触发
按这个顺序看,通常比盯一个字段名高效得多。
结语
Odoo 的补货日期看起来“会跳”,本质上是因为它不是单点算法,而是一条时间倒排链。
它会综合:
- 需求什么时候必须被满足
- 路由每一跳要提前多少天
- 采购这一步供应商要多少天
- 系统要不要提前几天就看见未来缺口
所以真正该记住的不是“某个字段代表交期”,而是:
补货日期 = 需求日期沿整条链路倒排后的触发时点。
理解这一点,很多“系统为什么今天又改主意了”的问题,就会变得非常可解释。
DISCUSSION
评论区