先说结论
Odoo 的供应商准时率 on_time_rate,不是按采购单张数算,也不是按收货单是否“整体准时”来算。
源码里它的真实口径是:
- 先找一定时间窗口内、已经有收货的采购行;
- 再找这些采购行对应的已完成
stock.move; - 只把完成日期不晚于采购行
date_planned的收货数量计入准时量; - 最后用“准时收货数量 / 采购行订购数量”算百分比。
所以这个指标本质上是在回答:
过去一段时间里,某供应商承诺给你的可采购数量,有多少是在计划日期前后按时交付的。
它是数量口径,不是单据张数口径。
第一步:它只统计最近一段时间,而且时间窗可配
_compute_on_time_rate() 先读系统参数:
purchase_stock.on_time_delivery_days
默认是 365 天。
然后只统计:
date_order在这个窗口内;qty_received != 0;order_id.state = 'purchase';- 产品类型不是
service。
这几个条件拼在一起,其实已经把很多“看上去像采购”的记录剔掉了:
- 还没确认的 RFQ 不算;
- 没有实际收货的采购行不算;
- 服务型采购不算;
- 太久以前的历史不算。
这很合理,因为供应商准时率必须建立在真实收货事实上,而不是建立在报价或服务交付感受上。
第二步:它看的是 move 完成时间,不是 PO 上肉眼看到的承诺状态
源码会再查一轮 stock.move:
purchase_line_id属于这些采购行;state = 'done'。
然后只保留:
move.date.date() <= move.purchase_line_id.date_planned.date()的 move。
这一步揭示了一个关键事实:
Odoo 把“准时”定义为收货 move 实际完成时间不晚于采购行计划日期。
不是看:
- PO 上的 receipt status;
- 采购员是否口头觉得供应商准时;
- 收货单整体有没有延期标签。
它用的是最硬的一条证据:done move 的日期。
第三步:它按数量记分,所以“部分准时”会得到部分分数
系统用 lines_quantity 把每条采购行中按时完成的 move 数量累加起来,然后:
- 分子 = 准时收货数量;
- 分母 = 采购行
product_uom_qty。
这意味着如果一条采购行订了 100 件:
- 80 件按时到;
- 20 件晚到;
那这条行给供应商贡献的就不是 0 分,也不是 100 分,而是 80%。
这比按单打勾更细,也更符合采购现实。
因为现实里供应商经常不是“全到 / 全不到”,而是:
- 先到一部分保生产;
- 剩余量延后;
- 有些批次提前,有些批次拖后。
如果 KPI 只能按整单判断,就会丢掉很多实际质量信息。
第四步:为什么它可能和你肉眼看到的“感觉”不一致
很多团队会说:
- “这家供应商明明很差,怎么准时率还可以?”
- “这单明明超期了,为什么 KPI 不是 0?”
通常原因就在口径差异:
1. 它按数量,不按单张数
一个大单部分准时,会拿到部分分。
2. 它只看 done move
还没完成的延期,不一定立刻体现在指标里。
3. 它用采购行 date_planned
如果采购员频繁改计划日期,KPI 会跟着新的计划口径走。
4. 它只统计非服务产品
某些你业务上很在意的服务迟交,在这里完全不计分。
所以这个指标不是“供应商全能评分”,而是:
围绕实物采购收货及时性的一种数量化视角。
第五步:_action_done() 的 acknowledge 动作说明它想把“收货完成”作为采购协同里的里程碑
在 purchase_stock/models/stock.py 里,stock.picking._action_done() 会先触发:
self.purchase_id.sudo().action_acknowledge()
再走父类完成逻辑。
这说明采购侧默认把收货完成看作一个明确的业务里程碑:
- 供应商交付这一步已经发生;
- 后面的准时统计、协同状态、跟催语义,都要建立在这个完成动作之上。
虽然 on_time_rate 具体计算用的是 move 的完成时间,但整个采购库存桥接层的思路是一致的:
- 用真实收货完成事件来支撑供应商绩效语义。
最容易误解的 5 个点
1. 以为它按采购单张数算
错。它按数量算。
2. 以为整单晚到就一定是 0 分
错。部分准时会得到部分分。
3. 以为未完成延期也会即时拖低指标
不一定。它主要看已完成 move。
4. 以为服务采购也进这个 KPI
不会。服务型产品被排除。
5. 以为 -1 是系统算错
不是。源码里用负值表示“没有可用数据”。
实战排错顺序
如果供应商准时率看起来不对,建议按这个顺序查:
- 系统参数
purchase_stock.on_time_delivery_days设了多少天; - 对应采购行是不是
purchase状态且已有qty_received; - 产品是不是服务;
- 相关
stock.move是否真的done; move.date与purchase_line.date_planned比较结果如何;- 采购员是否改过计划日期,导致 KPI 参照口径变化。
一句话记忆法
Odoo 供应商准时率衡量的不是“这张单准不准”,而是“过去一段时间订购的实物数量里,有多少按计划日期准时到货”。
DISCUSSION
评论区