先说结论
售后返厂后最常见的错误,不是操作慢,而是对象选错。
在 Odoo 里:
- Repair 处理的是“这件东西还作为成品存在,只是要修、换、拆、回收部分零件后再交付”
- Unbuild 处理的是“把这件成品按制造语义拆回组件”
- Scrap 处理的是“这批东西不要了,直接退出可用库存”
所以它们不是同义词,而是三种完全不同的库存与业务语义。
Repair:核心是“产品身份继续存在”
从 repair 模块源码看,维修单最核心的不是修理动作本身,而是:
- 原产品仍然是被维修对象
- 可以追加配件(
repair_line_type='add') - 可以拆出旧件(
remove) - 可以回收件(
recycle) - 完工时还会生成该成品自己的 stock move
action_repair_done() 里很明确:系统最后会为被维修产品再创建一条成品 move,并把零件 move 一并 done。
这说明 Repair 不是“拆了重组”,而是保持原产品身份不变的修复流程。
它还天然适合这些售后边界:
- 保修内换件,价格可能为 0
- 维修件与客户归属(owner)有关
- 维修中拆下的旧件与回收件要分别去不同库位
Unbuild:核心是“产品身份结束,组件身份恢复”
mrp.unbuild 的语义完全不同。
它假定你不再把返厂物当作“修好的那件成品”,而是要把它按 BOM 或原 MO 拆开。
源码里的 action_unbuild() 做的事情是:
- 校验 lot / serial 和来源 MO
- 生成 consume moves,把成品数量扣掉
- 生成 produce moves,把组件重新回到库存
- 在 tracked 场景下,尽量沿着原 MO 的 move lines 找对应 lot
也就是说,Unbuild 的重点不是维修,而是逆向制造。
它更适合这些场景:
- 成品返厂后决定拆零再用
- 需要恢复组件可用库存
- 希望保留与原制造单、lot/serial 的拆解追溯
Scrap:核心是“结束库存生命,不讨论修复或拆解收益”
stock.scrap 的源码非常直接:
- 从某个库位拿走数量
- 发往 scrap location
- 必要时触发 replenishment
它不关心维修步骤,不关心拆回哪些组件,也不保留“成品修好继续卖”这种语义。
因此 Scrap 最适合:
- 污染、损坏、失效,已无修复价值
- 即便能拆,也不值得拆
- 业务只想确认这批库存退出可用范围
三者最关键的判断标准,不是“坏没坏”,而是这 3 个问题
1. 这件东西的成品身份还要不要继续存在?
- 要继续存在:优先看 Repair
- 不再存在:看 Unbuild 或 Scrap
2. 你是否需要把组件重新回流库存?
- 需要:优先看 Unbuild
- 不需要:可能是 Repair 或 Scrap
3. 失败件还有没有经营价值?
- 有修复价值:Repair
- 有拆件再利用价值:Unbuild
- 都没有:Scrap
售后场景里最容易选错的 5 种情况
1. 把返厂维修做成 Scrap
结果库存是干净了,但保修、更换配件和客户交付链全丢了。
2. 把应该拆零回收的物品做成 Repair
结果系统保留了成品身份,但你真正想恢复的是组件库存。
3. 把没有原制造追溯的临时报废做成 Unbuild
结果 lot / serial 和来源逻辑反而变复杂。
4. 把全损件做成 Repair
系统会留下多余的维修与交付语义,实际并无修好可能。
5. 忽略 Repair 里的 remove / recycle 库位差异
拆下件、回收件和新增件并不是同一库存流向。
一个非常实用的决策表
- 客户返厂、更换零件后继续还给客户 → Repair
- 返厂后拆成可复用部件,成品身份结束 → Unbuild
- 返厂后确认无价值,直接销毁或隔离 → Scrap
- 保修内维修且新增配件不收费 → Repair
- 批次异常,整批拆回分析与回收 → Unbuild
- 质量事故、污染或超期失效 → Scrap
排错顺序
如果售后库存处理后账和实物流向不一致,按这个顺序查:
- 业务目标到底是修复、拆解还是退出库存
- 是否需要保留原成品身份与客户归属
- 是否需要把组件恢复为可用库存
- Repair 下 add/remove/recycle 的库位是否配置正确
- Unbuild 是否有对应 MO、lot/serial 与 BOM 支撑
- Scrap 是否只是为了图省事而被误用
一句话记忆法
Repair 保留成品身份,Unbuild 结束成品身份并恢复组件,Scrap 结束库存生命。售后返厂先分这三层,再谈操作。
DISCUSSION
评论区