先说结论
Odoo 的 lot / serial traceability 报表,不是单纯按 stock.lot 把相关单据列表堆出来。
它更像一套“沿着 move line 关系继续追”的规则系统。
源码里 stock.traceability.report 真正做的事情是:
从一批已完成的 move line 出发,再根据 MTO 关系或 MTS 库位流向,继续往前或往后把相关 move line 递归找出来。
所以追溯报表之所以能“越点越深”,核心不在 lot 这个字段本身,而在:
- 它把哪条 move line 当起点
- 它如何判断下一跳应该去哪里找
为什么“批次存在”不等于“追溯链就完整”
很多人会误以为:
- 只要产品开了 lot / serial
- Odoo 就天然有完整追溯图
其实不是。
追溯报表真正依赖的是:
- move line 有没有带上 lot
- move line 是否已经
done - 上下游 move / location 关系是否还能连起来
也就是说,lot 只是索引入口,真正把图串起来的是已完成的库存流动事实。
如果中间那条链没有 done move line,或者 lot 没被正确写进关键节点,追溯图就会断。
源码最值得看的地方:MTO 和 MTS 是两套回溯逻辑
stock.traceability.report._get_move_lines() 里有一个非常重要的分叉。
分支一:如果是 MTO
当 move_line.move_id.move_orig_ids 存在时,系统会去找:
- 上游 origin move 的 move lines
- lot 必须和当前 move line 相同
- 状态必须是
done
也就是说,在 MTO / 链式供给里,追溯优先相信的是:
这条库存流有明确的上游 move 关系。
这种追法偏“业务链”。
分支二:如果不是 MTO,而是普通 MTS
当没有上游 move 关系时,系统转而按事实流向查:
- 同产品
- 同 lot
- 某条 move line 的
location_dest_id等于当前行的location_id - 日期早于或等于当前行
- 状态是
done
这一步的意思很直白:
既然没有明确上游业务链,那我就按“这批货以前是谁送到这个位置的”来回溯。
这种追法偏“物理流”。
这就是为什么 traceability 报表经常“既像业务图,又像物流图”
很多人第一次看追溯报表会有一种感觉:
- 有时它像在沿着单据关系追
- 有时它又像在沿着库位搬运历史追
这不是错觉,而是源码本来就这样设计。
因为 Odoo 在追溯时其实混合了两类线索:
- 业务上的上游 / 下游 move 关系
- 库存事实上的 location 流转关系
MTO 更依赖前者,MTS 更依赖后者。
所以 traceability 报表不是一张单纯的 lot 清单,而是一张混合了供应链关系和库内流转的图。
为什么 scrap 和 inventory adjustment 也能进追溯图
在 _get_reference() 里,Odoo 会识别 move line 背后的 reference 类型。
它不只识别普通 picking,还会识别:
is_inventory对应 Inventory Adjustmentlocation_dest_usage == 'inventory' and scrap_id对应 Scrap
这点非常关键。
它说明 Odoo 对 traceability 的理解不是“销售 / 采购 / 制造单据追踪”,而是:
凡是改变了这条 lot 实际位置与状态的库存事实,都应该有资格进入追溯链。
所以你在追溯图里看到盘点修正、报废节点,不是附赠信息,而是它们本来就是这批货生命周期的一部分。
为什么 done 状态这么重要
源码里基本反复要求:
state == 'done'
这背后的逻辑非常合理:
- draft 是计划
- assigned 是预留
- waiting 是期待
- 只有 done 才是已经发生的库存事实
而追溯报表要表达的是“这批货到底经历了什么”,那就只能建立在已发生事实上,而不能把未执行计划混进去。
这也是为什么很多人感觉:
- 明明界面上看得到单据
- traceability 却没串上
因为你看到的是业务对象存在,系统追的是库存事实已落地。
调试 traceability 断链时,最该查什么
如果追溯图不完整,优先查这 5 件事:
1. lot / serial 是否真的落到了关键 move line 上
不是单据上有,而是 move line 上有。
2. 中间节点是否已经 done
没 done 就还不能进事实链。
3. 这段流程是 MTO 还是 MTS
两套回溯逻辑完全不同。
4. location 流转是否连续
MTS 下断链最常见就是位置接不上。
5. 有没有 scrap / inventory adjustment 把链路改向了
这些动作本来就会成为追溯节点。
新手最容易误解的 4 件事
1. 以为 traceability 只是 lot 的相关单据列表
其实它是 move line 图。
2. 以为 lot 开启后追溯天然完整
中间若没有 done move line,图照样断。
3. 以为它只认业务单据关系
MTS 下它会按 location 流向回溯。
4. 以为 scrap / adjustment 不算追溯节点
它们恰恰是 lot 生命周期的重要节点。
一句话记忆法
Odoo 的 traceability 报表不是“批次相关单据列表”,而是从 done 的 move line 出发,按 MTO 业务链或 MTS 位置流递归追出来的一张库存事实图。
理解这句话,你以后看 lot / serial 追溯,就不会只盯着 stock.lot 那一张表了。
DISCUSSION
评论区