先说结论
Odoo 里的 consumption method,不是在说“能不能改数量”这么简单。
它真正控制的是:
- BOM 理论用量和实际消耗不一致时,系统怎么处理
- MO 在
Mark as Done前要不要弹警告 - 哪些情况下普通用户能关单,哪些情况下必须经理介入
一句话记:
consumption 不是领料录入方式,而是制造完工前对“理论消耗 vs 实际消耗”的容忍策略。
三种策略到底分别是什么意思
在 mrp.bom 和 mrp.production 上,官方给了三档:
flexible:Allowedwarning:Allowed with warningstrict:Blocked
帮助文本已经写得很清楚:
- Allowed:允许偏离 BOM 用量
- Allowed with warning:允许偏离,但关单时要汇总提醒差异
- Blocked:不符合 BOM 消耗时,只有经理才能关制造单
也就是说,这不是前端展示文案差异,而是完工控制强度的分级。
Odoo 到底怎么判断“消耗不一致”
关键逻辑在 mrp.production._get_consumption_issues()。
这段源码做了两步比对:
第一步:先算理论应耗
系统会通过 _get_moves_raw_values() 重新推一次 BOM 对应的原料行,然后按照:
- 当前
qty_producing - BOM 数量比例
- UoM 换算
把每个产品理论上应该消耗多少算出来。
注意这里不是死拿原单初始数量,而是会按本次实际要完工的数量缩放。
第二步:再算实际已领
系统再去遍历 move_raw_ids,取每个 move 的 _get_picked_quantity()。
这里很关键:
- 看的是 picked / 实际登记的消耗
- 不是只看原始需求数量
- 对 BOM 里不存在但你额外领掉的料,也会单独记成 issue
所以 Odoo 比较的是:
理论应该耗多少,和你这次真正登记消耗了多少。
不是“move 上原始 demand 改没改”。
为什么 flexible 看起来“最宽松”,但也不是完全没规则
源码里如果 order.consumption == 'flexible',_get_consumption_issues() 会直接跳过这单。
这意味着:
- 系统不会因为偏耗去拦你
- 也不会弹 consumption warning wizard
但这不代表所有数据都自动合理。
flexible 只是说:
系统允许业务现实先落地,再由人自己承担偏耗解释。
所以它更适合:
- 工艺波动较大
- 现场按实际投料
- BOM 只做参考,不做强控制
不适合:
- 成本核算高度敏感
- 差异必须闭环追责
- 需要严格按配方发料的行业
warning 真正的价值是什么
很多团队觉得 warning 很鸡肋:既然最后还是能关,那弹窗有什么意义?
但从源码看,warning 的价值在于:
- 它不会阻断正常业务
- 但会在完工收口前把差异正式暴露出来
_action_generate_consumption_wizard() 会把这些差异整理成行:
- 哪张 MO
- 哪个产品
- 实际消耗多少
- 理论应该多少
- 当前 consumption 策略是什么
这非常适合大多数制造团队。
因为现实里最常见的问题不是“永远不允许偏差”,而是:
允许偏差,但不允许悄悄偏。
warning 正好对应这种管理方式。
strict 为什么不是“绝对不能多耗少耗”
严格来说,strict 更接近:
出现偏差时,普通制造用户不能自己把这张 MO 当作没事发生一样关掉。
帮助文本里说的是“only a manager can close a manufacturing order when the BoM consumption is not respected”。
所以它不是数学上禁止偏差,而是组织权限上提高了门槛。
这很符合真实工厂管理:
- 偏差可能 unavoidable
- 但必须由更高权限的人确认
因此 strict 更像强审批控制,而不是物理禁止。
Manual Consumption 为什么经常把人绕晕
在 stock.move 上,Odoo 还有 manual_consumption。
帮助文本写得很直接:
- 开启后,这个组件的消耗要手工登记
- 如果没开启,但你手工改了组件消耗,Odoo 也会认为它进入 manual consumption 语义
很多人会把它和 consumption method 混成一件事。
其实它们是两层:
- consumption method:偏耗时怎么判
- manual consumption:消耗是系统自动带,还是要人工明确登记
这就是为什么源码里一边有 _determine_is_manual_consumption(),另一边又有 _get_consumption_issues()。
一个管录入方式,一个管差异校验方式。
为什么 extra lines 也会被抓出来
源码里有个很容易被忽略的分支:
如果某个实际消耗的产品,根本不在理论 BOM 结果里,但你确实 picked 了非零数量,系统也会把它记成 issue。
这意味着 Odoo 并不是只检查“原有 BOM 行数量对不对”,它还检查:
你有没有多领了 BOM 根本没定义的料。
这对排查现场临时替料、错料、补投临时件特别有用。
实战里最容易踩的 5 个坑
1. 把 consumption method 当成“自动扣料方式”
不是。它主要管的是完工前差异容忍。
2. 以为 warning 只是烦人的弹窗
它本质上是差异正式曝光机制。
3. 以为 strict 代表系统绝对不让偏耗发生
更准确地说,是普通用户不能无视偏差直接收口。
4. 把 manual consumption 和 consumption method 混为一谈
一个管录入,一个管校验。
5. 只盯 BOM 原有行,不看额外领料行
额外 picked 的产品一样会触发 issue。
该怎么选
经验上可以这样理解:
- flexible:现场自由度最高,适合高波动环境
- warning:最平衡,适合大多数制造团队
- strict:适合强配方、强成本、强审计行业
如果团队还没建立稳定的现场数据纪律,别一上来就 strict。
否则最后常见结果不是“更规范”,而是大家想办法绕系统。
一句话记忆法
Odoo 的 consumption method 管的不是怎么领料,而是制造关单前,系统对实际消耗偏离 BOM 的容忍与升级处理方式。
DISCUSSION
评论区