先说结论
在 Odoo 制造里,成品批次号 / 序列号不是“完工前填个文本框”这么简单。
lot_producing_ids 这组数据会同时影响:
- 成品数量
qty_producing - 序列号合法性校验
- finished move 上的 lot 归属
- 原料 move line 与成品 move line 的追溯映射
一句话记:
制造中的 lot_producing_ids,不只是标签,而是成品身份与追溯链的核心锚点。
为什么 Odoo 要把“正在生产的 lot”单独建模
很多新手会问:
- 原料 move line 已经有 lot 了
- 成品 move line 完工后也会有 lot
- 为什么制造单上还要有
lot_producing_ids
因为制造过程里,系统需要先知道:
- 这次准备产出的成品是谁
- 这次准备产出多少个序列号
- 这些身份要不要在完工前就参与校验和联动
也就是说,lot_producing_ids 是“生产中的成品身份集合”,不是纯粹的结果回填字段。
它会怎么影响 qty_producing
在 addons/mrp/models/mrp_production.py 里,_change_producing() 有一段非常关键的逻辑:
- 如果成品 tracking 是
serial,并且已经选了lot_producing_ids - 那么
qty_producing直接等于序列号个数
这意味着:
对序列号产品
你不是先说“我要做 10 个”,再随便补 10 个 SN。
而是你一旦录入了 10 个序列号,系统就会把“本次生产数量”理解成 10。
对 lot 管理产品
逻辑又不一样。
源码里还专门限制:如果 tracking 是 lot,lot_producing_ids 不能超过 1 个。
也就是说:
- lot 跟踪:一批产出对应 1 个成品 lot
- serial 跟踪:每个产出单位对应 1 个序列号
Odoo 这里不是前台体验问题,而是在底层就把两种追踪粒度明确区分了。
自动生成序列号到底做了什么
action_generate_serial() 这段源码很值得看。
它不是简单“生成一个字符串”,而是按不同 tracking 模式走不同分支:
如果是 lot 跟踪
- 只能有 1 个成品 lot
- 如果已经存在,再生成会直接报错
- 生成后会把 lot 放进
lot_producing_ids
如果是 serial 跟踪
- 当数量为 1 且尚未生成时,可以直接创建一个序列号
- 如果数量更大,系统会打开专门的序列号分配动作,让你按批量规则处理
这背后的设计很合理:
- 批次号场景重在“一批身份”
- 序列号场景重在“多单位唯一身份”
所以自动生成不是一个统一按钮,而是两种产品追踪策略的不同实现入口。
Odoo 为什么还要专门校验序列号
在 _can_produce_serial_numbers() 里,官方会对 lot_producing_ids 逐个检查。
它会调用 stock.quant 的序列号校验逻辑,确认这些 SN 对当前产品、当前公司是否可用。
这说明 Odoo 很明确地不允许“制造现场先随便写,事后再纠正”。
因为一旦 SN 冲突,你影响的不只是这张 MO,而是整条追溯链。
所以系统会尽量在录入阶段就把问题拦住。
成品 lot 是怎么落到 finished move 上的
源码里在制造单准备完工时,会遍历主成品 finished move:
- 如果该 move 需要 tracking
- 且 move 上还没有 lot
- 就把
order.lot_producing_ids赋给 move 的lot_ids
这一步很关键。
它说明:
lot_producing_ids不是停留在 MO 头上的临时字段- 它会真正下沉到 finished move / move line
- 后续库存入库、追溯、报表都是基于这些实际 move 数据继续走
所以如果成品 lot 没绑对,不只是“单据看着别扭”,而是成品库存身份本身就歪了。
为什么它还会影响追溯报表
在 addons/mrp/models/stock_move_line.py 里,Odoo 对制造完成后的原料 move line 做了一步额外映射:
- 先拿到本制造单的
lot_producing_ids - 再把对应的 finished move lines 找出来
- 最后把这些 produced lines 反向挂到原料 move line 的
produce_line_ids
这一步的业务意义非常大:
原料批次和成品批次之间的追溯关系,不是凭空猜出来的,而是靠制造单上的 lot 身份明确建立起来的。
所以如果你觉得 traceability report 能“一路串起来”很神奇,关键锚点之一就是 lot_producing_ids。
新手最容易误解的几个点
1)lot_producing_ids 不是备注字段
它会改 qty_producing、会触发校验、会参与完工与追溯。
2)lot 与 serial 的录入语义完全不同
lot 是一批一个身份,serial 是一件一个身份。不要用同一套习惯去理解这两个模式。
3)finished move 上后来能看到 lot,不代表前面的 lot_producing_ids 不重要
恰恰相反,后面的绑定很多时候就是从这里传下去的。
实战里该怎么用
如果你们做的是受监管、可追溯要求高的制造场景,比如食品、医疗、电子、精密零件,这套逻辑尤其重要。
建议关注三件事:
- 产品 tracking 策略先定清楚:是 lot 还是 serial
- 现场录入不要把 lot/SN 当“最后补资料”
- 出现追溯断链时,先回头查 MO 上的
lot_producing_ids是否建立正确
最后总结
Odoo 对制造成品身份的设计非常一致:
- 制造单先维护“本次将产出的批次 / 序列号”
- 这些身份反过来约束
qty_producing和合法性 - 完工时再把身份落到 finished moves
- 追溯报表继续基于这些 lot 关系把原料与成品串起来
所以成品批次号在 Odoo 里绝不是“最后录一下”的附件数据,而是:
制造执行、库存身份和追溯链路共同依赖的一根主线。
DISCUSSION
评论区