条码质量闸门

Odoo 条码制造为什么不让你直接点完成:质量闸门、quality_check_todo 与最终放行链路讲透

很多团队以为条码端扫完成品、数量够了就该直接完工,但 Odoo 企业版会在制造条码流里插入一层质量闸门。本文结合 quality_mrp 与 stock_barcode_quality_mrp 源码,讲清为什么 Validate 会被藏起来。

企业 制造
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 8 阅读

先说结论

在 Odoo 企业版里,条码制造不是“扫码够数就完工”

只要这张制造单还有待做的质量检查,系统就会主动把条码页里的 Validate / Produce 按钮收起来,逼着你先走 Quality Checks

这不是前端小把戏,而是一条完整链路:

  1. quality_mrp 先在 MO 上生成并计算待处理检查
  2. stock_barcode_quality_mrp 再把 quality_check_todo 暴露给条码前端
  3. 条码模型根据这个字段决定是否显示最终验证按钮
  4. 只有检查通过后,制造单才允许继续 button_mark_done

一句话说透:

Odoo 在条码制造场景里把“完工动作”改造成了“先过质量闸门,再允许完工”。

这篇文章为什么和已有“制造质量检查”不是一回事

站内已经有一篇泛讲 quality_mrp / quality_mrp_workorder 的文章,重点是“质量检查如何嵌入制造步骤”。

但这篇要解决的是一个更细、也更容易让现场困惑的问题:

  • 为什么在桌面表单里能看到质量按钮
  • 到了条码枪 / 条码页却像“完成按钮失踪”
  • 扫码数量明明已经够了,系统还是不让过

这个切口主要落在 stock_barcode_quality_mrp,也就是制造条码流里的质量阻塞逻辑,不是泛泛讲质检概念。

第一层:质量检查在 MO 上是怎么长出来的

真正的源头在 quality_mrp/models/stock_move.py

stock.move._action_confirm() 在标准确认逻辑之后,会继续调用:

  • _create_quality_checks_for_mo()

这一步会按生产单把 move 分组,然后去搜对应的 quality.point,再生成 quality.check

源码里至少覆盖了三类制造质检入口:

  • measure_on = 'product'
  • measure_on = 'move_line'
  • measure_on = 'operation'

也就是说,条码页里后来看到的“还没做完的质检”,不是前端临时推出来的,而是在 MO 确认和 move 建立阶段就已经准备好的。

这里有两个细节很关键:

1. 成品级质量点会挂到 production_id

生成检查值时,_create_quality_checks_for_mo() 会给检查补上:

  • production_id = production.id

这让后面的所有逻辑都知道:这张检查单属于哪张制造单。

2. 制造场景下不是所有质量类型都能乱配

quality_mrp/models/quality.py 里有约束:

  • 如果 measure_on == 'move_line'
  • picking_type 是制造工序类型
  • 系统会直接报错

也就是源码明确阻止某些“数量型质检 + 制造工序类型”的错误组合。

所以现场如果觉得“为什么我配完质量点却不按预期工作”,别先怪条码页,先回头看质量点定义是否真的符合制造场景约束。

第二层:quality_check_todo 才是条码页真正盯着的信号

quality_mrp/models/mrp_production.py 里,mrp.production 被加了几个关键字段:

  • check_ids
  • quality_check_todo
  • quality_check_fail

其中最重要的是:

  • quality_check_todo = fields.Boolean(compute='_compute_check')

_compute_check() 的逻辑不复杂,但非常关键:

  • 只要有任意 check_ids.quality_state == 'none'todo = True
  • 只要有任意 check_ids.quality_state == 'fail'fail = True

最后结果写回:

  • production.quality_check_todo = todo
  • production.quality_check_fail = fail

这意味着对条码前端来说,它根本不需要理解每一条检查单细节。

它只要盯住一个布尔量:

  • 这张 MO 现在还有没有没做完的质量检查

有,就卡住。 没有,才放行。

这就是一个很典型的 Odoo 设计:

  • 后端把复杂语义折叠成简单状态
  • 前端只围绕状态做行为切换

第三层:条码页为什么能“知道”这张 MO 有待检项目

这一步在 stock_barcode_quality_mrp/models/mrp_production.py,代码非常短,但价值极大。

它重写了:

  • mrp.production._get_fields_stock_barcode()

然后往条码初始状态里追加:

  • quality_check_todo

别小看这行代码。没有它,条码前端根本拿不到这个字段。

也就是说,quality_mrp 负责定义质量状态,stock_barcode_quality_mrp 负责把这个状态送进条码客户端的首屏载荷

很多人看企业版源码时会低估这种“小 patch”,但它往往正是业务行为切换的开关。

第四层:Validate 按钮为什么会消失

真正的“闸门”在 stock_barcode_quality_mrp/static/src/models/barcode_mrp_model.js

这个模块 patch 了 BarcodeMRPModel,做了两件事:

1. 指定打开质量检查的方法

openQualityChecksMethod: "check_quality"

也就是条码端点 Quality Checks 时,不是自己拼界面,而是回调后端的:

  • mrp.production.check_quality()

而这个方法在 quality_mrp/models/mrp_production.py 里会筛出:

  • quality_state == 'none' 的检查单

然后打开质量检查向导。

2. 更关键:直接改写 displayValidateButton

get displayValidateButton() {
    return !(this.record && this.record.quality_check_todo) && super.displayValidateButton;
}

这段逻辑可以直接翻译成人话:

  • 当前记录存在
  • quality_check_todo 为真
  • 那就不要显示 Validate 按钮

而基础条码模板 stock_barcode/static/src/components/main.xml 本来就是:

  • t-if="env.model.displayValidateButton"

所以不是按钮“灰掉”,不是按钮“点了报错”,而是按钮根本不渲染

这就是为什么一线用户最常见的抱怨是:

  • “我条码页上的完成按钮怎么没了?”

因为系统做的不是温和提醒,而是明确的 UI 闸门。

第五层:就算前端绕过去,后端也还会再拦一次

如果你以为这只是前端隐藏按钮,那就把 Odoo 想得太松了。

quality_mrp/models/mrp_production.py 里还有:

  • pre_button_mark_done()
  • _check_qc_status()

_check_qc_status() 会检查:

  • check_ids 里是否还存在 quality_state == 'none'

如果还有未完成检查,pre_button_mark_done() 就会:

  • 向导场景下弹 warning 通知
  • 普通场景下直接抛 UserError("You still need to do the quality checks!")

所以这套机制是双保险:

  • 前端先不让你点完成
  • 后端再保证你就算点到了也过不去

这才是企业版“流程控制”该有的样子。

官方测试把这条链路写得很直白

stock_barcode_quality_mrp/tests/test_barcode_quality_mrp_flows.py 和对应 tour 很值得看。

测试流程基本是:

  1. 建一个有 BOM 的成品
  2. 建一个 measure_on = 'product' 的质量点
  3. 打开 /odoo/barcode
  4. 进入 Manufacturing
  5. 新建制造单
  6. 扫成品条码 love724
  7. 点击增加数量,让 qty_producing 达到可完工状态
  8. 点击 Quality Checks
  9. 在弹窗里点 do_pass
  10. 回到条码页点击 .o_validate_page
  11. 断言出现成功通知
  12. 最后确认 quality.check.quality_state == 'pass',且 production_id.state == 'done'

这个测试说明了三个事实:

1. 条码制造里的质量检查不是旁路功能

它被写进官方 tour,说明这是标准完成路径的一部分。

2. 先做质量,再做最终验证,是有严格顺序的

测试不是先 validate 再补检查,而是相反。

3. 质量通过后,MO 才真正进入 done

也就是说,质检不是装饰数据,而是完工状态机的一段前置条件。

这套设计对车间现场意味着什么

如果你在现场推条码制造,这条链路会直接影响培训和 SOP。

1. 扫码员不能只学“扫料、扫成品、点完成”

他们还必须理解:

  • 什么时候系统会要求先做质量检查
  • 为什么按钮会暂时消失
  • 质检通过后按钮为什么又回来了

2. 质量员和操作员的职责边界会更清晰

因为系统已经把“未检不可完工”固化成界面行为,不再只是口头纪律。

3. 自定义条码前端时,最容易把这条闸门误删

很多团队改条码页时只盯着按钮布局,忘了 displayValidateButton 这种 getter 背后藏着业务控制。

一旦你重写前端却没把 quality_check_todo 带上,或没保留这个条件判断,就会出现:

  • 现场可以提前完工
  • 但后端 later 才报错
  • 用户体验变得很割裂

更糟的是,如果你连后端保护也改坏了,就真的把质检闸门拆掉了。

最常见的 5 个排错点

1. 条码页没有 Quality Checks,也没有 Validate

先看条码载荷里有没有 quality_check_todo,以及 openQualityChecksMethod 是否还指向 check_quality

2. 明明配置了质量点,却从没触发

回头查 stock.move._create_quality_checks_for_mo() 是否真的搜到了对应 quality.point,尤其是:

  • measure_on
  • picking_type_ids
  • 产品 / 产品类别范围

3. 质量检查做完了,按钮还是不回来

先确认检查状态是否从 none 变成 pass / fail,再看条码页关闭向导后是否触发 refresh。

4. 用户能从别的入口把 MO 标记完成

重点查有没有自定义覆盖 pre_button_mark_done()_check_qc_status()

5. 失败后流程不符合预期

这篇主讲的是“条码端完工闸门”,但如果你希望失败后改库位、打告警、走隔离流程,还要继续往 quality_mrpfailure_location_idquality.alert 和相关向导逻辑查。

我对这段源码的判断

我挺喜欢这段设计,因为它很克制。

stock_barcode_quality_mrp 自己几乎没发明新业务对象,只做了三件小事:

  • quality_check_todo 暴露到条码前端
  • 告诉条码端该调用哪个质量入口
  • 用一个 getter 决定是否渲染 Validate 按钮

但就是这几个小 patch,把“质量先于完工”的企业规则稳稳塞进了现场执行流。

这比做一堆醒目的红字提醒更有效,因为用户根本没有跳过流程的主路径

一句话总结

在 Odoo 企业版制造条码流里,quality_check_todo 不是提示字段,而是完工闸门;它让系统在 UI 和后端两层同时保证“先质检,后完工”。

DISCUSSION

评论区

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