先说结论
序列号产品在 Odoo 里看起来最反直觉的一点是:
- 制造单可以有总数量
- 但执行时又总是被拉回到“一个序列号对应一个产出单位”
这不是界面故意找麻烦,而是 Odoo 在保护追溯语义。
一句话说透:
对 serial tracked 成品,制造单可以按批下达,但执行层必须回到逐件确认,因为每一件都要有自己独立的身份。
源码里这套逻辑主要围绕:
lot_producing_idsqty_producing_change_producing()/_set_qty_producing()action_generate_serial()pre_button_mark_done()
为什么序列号产品不能只靠 product_qty
对普通未追踪产品,product_qty = 100 大多数时候就足够表达生产目标。
但对序列号产品来说,数量只是“总任务”,还不是“可追溯结果”。
因为业务真正需要的是:
- 做了几件
- 每件叫什么序列号
- 后续每件对应哪些原料、工序、售后记录
所以在 mrp.production.py 里,Odoo 给 serial 场景额外强调:
lot_producing_ids:本次要产出的成品序列号集合serial_numbers_count:序列号数量qty_producing会和这些序列号数量发生强绑定
也就是说,在 serial 场景里,数量只是结果之一,序列号集合才是执行真相。
qty_producing 为什么会被序列号数量“拉回去”
在 _change_producing() 里有个关键判断:
- 如果产品追踪方式是
serial - 且存在
lot_producing_ids - 那么
qty_producing = len(lot_producing_ids)
这句非常重要。
它等于直接宣布:
对于序列号制造,当前准备产出的数量,不由你自由输入决定,而由你实际准备好的序列号数量决定。
这就是为什么现场经常出现这种感觉:
- 我明明想先把
qty_producing改成 10 - 但系统还是要求我先准备 10 个序列号
不是 Odoo 啰嗦,而是如果没有 10 个独立 serial identity,系统就不认为你真的准备好了 10 件可追溯成品。
_set_qty_producing() 为什么还会再校正一次
在 _set_qty_producing() 里,serial 产品会再次检查:
qty_producing_uomqty_production_uomlen(lot_producing_ids)
如果当前 qty_producing 和应有逻辑不一致,系统会把它重新换算回以序列号数量为准的值。
这说明 Odoo 的设计不是“前端 onchange 提醒一下”而已,而是:
- onchange 会管一次
- 真正重算生产数量时再管一次
也就是说,这是一条核心规则,不是 UX 建议。
自动生成序列号时,为什么有时直接生一个,有时弹向导
在 action_generate_serial() 里,serial 产品有两种路径:
情况一:product_qty == 1 且当前还没序列号
系统会直接创建一个 lot/serial,并把:
qty_producing = 1- 然后调用
set_qty_producing()
这适合典型的单件生产。
情况二:总数量不止 1
系统不会替你偷偷一次性全做完,而是打开 action_assign_serial_numbers 向导。
这背后的业务含义很清楚:
- 单件生产,自动补一个序列号没什么歧义
- 多件生产,必须让用户明确本次到底生成多少个、命名区间怎么走、是否真的要逐件落号
所以向导不是多余步骤,而是多件 serial 生产的责任确认界面。
完工前为什么一定盯 lot/serial
在 pre_button_mark_done() 里,Odoo 会先做一个关键判断:
- 如果这张制造单按规则必须自动检查追踪信息
- 但
lot_producing_ids还没有 - 系统就不让你直接完工
并且会返回 action_generate_serial()。
这条链路说明:
对 serial 成品来说,完工不是“数量够了就行”,而是“每一件的身份先落地,再谈完工”。
这和很多新手心里的模型正好相反。
他们以为序列号只是完工后的补充属性;但在 Odoo 这里,序列号是完工成立条件的一部分。
业务上为什么必须这样设计
因为序列号产品通常意味着更高追溯要求,例如:
- 设备整机
- 高价值单件产品
- 售后保修依赖 SN
- 质量问题要追到单体
如果允许用户先完工 10 件、后面再慢慢补序列号,就会出现严重歧义:
- 哪 10 件先做完了
- 每件用的是哪批组件
- 哪件已经交付、哪件还在库
所以 Odoo 宁愿让执行界面更“麻烦”一点,也要把追溯语义锁死。
新手最容易误解的点
1)一张 MO 多数量,不代表可以不逐件落号
MO 的总数量是任务视角;serial number 是执行与追溯视角。
2)qty_producing 不是在 serial 场景下完全自由
只要 lot_producing_ids 已经存在,数量就会被这些序列号数牵着走。
3)自动生成序列号不等于系统会替你无脑生成整批
单件可以自动,多件通常要通过向导明确确认。
4)完工前缺序列号不是小问题
它不是单纯“资料还没补完”,而是这批产出在 Odoo 看来还没有形成可追溯成品。
实施与开发注意点
一,不要把 serial 生产按普通批量生产讲给现场
培训时要先讲清:
- 计划可以按批
- 追溯必须逐件
这一步不讲清,后面大家只会觉得系统“卡人”。
二,批量导码或自定义生码时,要尊重 lot_producing_ids -> qty_producing 的主从关系
很多二开喜欢先强塞 qty_producing,再补 lot。这样极易造成界面值和源码重算不一致。
更稳妥的做法通常是:
- 先准备序列号集
- 再让系统顺着
_change_producing()/_set_qty_producing()去落数量
三,排错时优先看三件事
- 产品 tracking 是否为
serial lot_producing_ids里到底有多少个序列号- 完工前是不是被
pre_button_mark_done()拉去补序列号
最后总结
Odoo 对序列号制造的核心立场非常稳定:
- 制造任务可以批量下达
- 但执行确认必须逐件可追溯
- 数量不是唯一真相,序列号集合才是
- 没有序列号,就不算真正完成可追溯成品
一句话记住:
Serial MO 可以批量计划,但只能逐件成立。
DISCUSSION
评论区