制造报废

Odoo 制造报废为什么不只是“扔掉一点料”:MO、工单、来源库位与追溯链讲透

制造场景里的 Scrap 会跟着 MO、工单、原料或成品方向走,不同状态下取库位也不一样。搞不清这件事,报废就会把追溯和估值一起搞乱。

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

先说结论

Odoo 里的制造报废,不是“库存模块里的 Scrap 按钮搬到制造里”而已。

一旦 Scrap 带上 production_idworkorder_id,它就不再是普通库存损耗记录,而是进入了制造语义:

  • 它属于哪张 MO
  • 是原料报废还是成品报废
  • 应该从哪个库位扣
  • 是否要保留对工单与追溯链的解释能力

所以真正的问题不是“能不能报废”,而是这次报废到底是在制造链上的哪个位置发生

源码里最关键的两件事

stock.scrap 的 MRP 扩展里,有两个很重要的字段:

  • production_id
  • workorder_id

这已经说明 Odoo 不把制造报废看成无上下文动作,而是允许你把 Scrap 直接挂到:

  • 整张制造单
  • 某一道工单

这两种挂法的业务含义不一样:

  • 挂 MO:更偏整单层面的原料或成品异常
  • 挂工单:更偏具体工序现场发生的损耗

为什么库位会“自动变来变去”

_compute_location_id() 的逻辑很值得看:

  • 如果 Scrap 关联 production_id,且 MO 还没 done,默认从 location_src_id 取货
  • 如果 Scrap 关联 production_id,但 MO 已经 done,默认从 location_dest_id 取货
  • 如果是 workorder_id,则走该工单所属 MO 的原料来源库位

这背后的业务语义非常清楚:

完工前报废,多数是在“待消耗原料”这一侧;完工后报废,多数已经站到“成品侧”了。

所以你看到同样是制造报废,却在不同时间点扣不同库位,不是系统乱跳,而是 Odoo 在替你判断“这次报废更像原料损耗还是成品异常”。

为什么有时报废 move 会挂到 production_id,有时挂 raw_material_production_id

_prepare_move_values() 里,Odoo 会区分报废的产品是不是这张 MO 的 finished product:

  • 如果报废的是成品集合中的产品,move 记到 production_id
  • 否则记到 raw_material_production_id

这件事非常重要,因为它决定后续 traceability、统计、以及你回头查“这笔损耗到底属于原料端还是成品端”时,系统怎么归类。

批次 / 序列号为什么更敏感

如果报废的是 serial 跟踪产品,且 Scrap 关联了制造单,Odoo 还会借助 stock.quant._check_serial_number() 做额外检查,并可能给出推荐库位。

换句话说,制造报废并不是简单写一笔数量。对序列号产品,它还在防你做出一笔不符合真实存放位置或追溯逻辑的报废。

最容易误解的地方

1. 以为工单报废只是备注

不是。workorder_id 会让这笔损耗更靠近具体工序上下文。

2. 以为报废一定都从原料库扣

完工前后,默认源库位逻辑不同。

3. 以为制造报废不会影响补货

如果 MO 有 production_group_iddo_replenish() 还会把这层生产组上下文带过去,影响后续补货链。

4. 以为 Scrap 只影响库存数量

它也会影响追溯解释、MO 成本理解以及现场责任定位。

正确排错顺序

遇到制造报废“扣错库位”或“挂错对象”,按这个顺序查:

  1. Scrap 是挂 MO 还是挂工单
  2. 当前 MO 是否已经 done
  3. 报废的是成品还是原料
  4. 是否有 lot / serial 校验干预
  5. 是否触发了带 production_group_id 的补货上下文

一句话记忆法

Odoo 制造报废不是单纯减库存,而是在回答:这次损耗发生在制造链的哪一段。

DISCUSSION

评论区

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