供应商 KPI

Odoo 供应商准时率怎么算才不失真:收货历史、计划日期与 on-time KPI 口径边界讲透

Odoo 的供应商准时率不是“按采购单张数算准时”,也不是“按收货单是否逾期”这么粗。`purchase_stock` 实际按采购行数量、计划日期与已完成 stock move 的完成时间来算,而且部分准时会部分记分。本文把这个 KPI 的真实口径和误区一次说清。

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

先说结论

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 是系统算错

不是。源码里用负值表示“没有可用数据”。


实战排错顺序

如果供应商准时率看起来不对,建议按这个顺序查:

  1. 系统参数 purchase_stock.on_time_delivery_days 设了多少天;
  2. 对应采购行是不是 purchase 状态且已有 qty_received
  3. 产品是不是服务;
  4. 相关 stock.move 是否真的 done
  5. move.datepurchase_line.date_planned 比较结果如何;
  6. 采购员是否改过计划日期,导致 KPI 参照口径变化。

一句话记忆法

Odoo 供应商准时率衡量的不是“这张单准不准”,而是“过去一段时间订购的实物数量里,有多少按计划日期准时到货”。

DISCUSSION

评论区

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