制造补货

Odoo 制造补货到底走订单触发还是补货规则:Orderpoint、MTO 与 Manufacture 路线边界讲透

同样都会生成制造单,但 Orderpoint 补货、MTO 需求触发和手工 Replenish 的业务语义完全不同。源码里最关键的不是‘会不会建 MO’,而是谁带着 bom、日期和需求上下文进来。

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

先说结论

在 Odoo 里,“生成制造单”只是结果,不是机制本身。

真正重要的问题是:

  • 需求是谁发起的
  • BOM 是谁决定的
  • 计划日期怎么算的
  • 这张 MO 属于预测补货,还是属于订单拉动

一句话记:

MTO 更像“有单就拉”,Orderpoint 更像“缺量就补”,而 Manufacture 路线负责把这两类需求翻译成 MO。

如果只盯着“系统最后建没建制造单”,就很容易把 Odoo 的制造补货逻辑看扁。


为什么这个问题在实施里总出错

现场常见困惑是:

  • 为什么两个产品都走 Manufacture,却一张 MO 跟销售单绑得很紧,另一张像系统自己补出来的
  • 为什么补货规则里选了 BOM,生成单据用的就是那个;而有些场景又像系统自己找默认 BOM
  • 为什么有时 scheduler 跑完看到 draft MO,过一会儿才 confirmed

这些问题背后,其实是三套对象在一起工作:

  • stock.warehouse.orderpoint
  • stock.rule
  • mrp.production

再加上 mrp.bom 对 lead time、BOM 选择和补货单位的影响。


Orderpoint 在制造补货里到底多做了什么

addons/mrp/models/stock_orderpoint.py 不是简单给补货规则多挂了一个 BOM 字段。

它实际上补上了制造补货最关键的上下文。

1. orderpoint 可以显式指定 BOM

字段包括:

  • bom_id
  • effective_bom_id
  • bom_id_placeholder

意思是:

  • 你可以在补货规则里直接指定要用哪张 BOM
  • 如果没指定,系统再去找默认匹配 BOM

这解决的是多 BOM 产品最容易出错的问题:

不是“这个产品能制造”就够了,而是“这次补货到底按哪张 BOM 制造”。

2. orderpoint 会把 BOM 带进 procurement values

源码里 _prepare_procurement_values() 明确把:

  • bom_id

塞进了后续采购/制造链。

这一步很关键。

因为如果这层上下文丢了,后面 stock rule 只能重新猜 BOM,结果就可能和补货规则页面看到的不一致。

3. orderpoint 会影响 days_to_order

MRP 扩展了 _compute_days_to_order(),当补货规则走 manufacture 时,会优先看 BOM 的:

  • days_to_prepare_mo

也就是说,制造补货不是只看最小/最大库存,还会把“组件提前准备时间”纳入计划。


Manufacture route 怎么把需求翻译成 MO

真正把需求变成制造单的核心,在 addons/mrp/models/stock_rule.py

_get_matching_bom():先看上下文,再看默认

BOM 选择顺序很有代表性:

  1. 如果 values 里已经有 bom_id,优先用它
  2. 否则如果 orderpoint_id 上有 BOM,优先用补货规则上的
  3. 再不行才用系统默认 _bom_find()

这说明官方非常明确:

制造补货的 BOM 选择优先级,先尊重业务上下文,再退回系统默认。

_prepare_mo_vals():把需求语义写进 MO

准备 MO 时,系统会写入:

  • orderpoint_id
  • bom_id
  • date_start
  • date_deadline
  • reference_ids
  • move_dest_ids

所以生成出来的 MO,不只是一个产品+数量对象,而是带着来源语义的执行节点。

如果它来自 orderpoint,MO 上就能看见 orderpoint_id;如果它来自订单拉动,下游 move 关系又会体现另一套语义。

_make_mo_get_domain():有些需求会尝试并到已有 MO

这段逻辑很容易被忽视。

当有 orderpoint_id 时,系统会根据:

  • date_deadline
  • date_start
  • BOM
  • 产品
  • picking type

去找是否存在可复用的 draft / confirmed MO。

这也是为什么某些制造补货看起来像“没有新建单,而是并到旧单里”。

不是系统玄学,而是 stock rule 在尝试复用合适的未计划 MO。


MTO 和 Orderpoint 的制造语义到底差在哪

MTO:需求跟着具体下游对象走

MTO 的核心不是“必须制造”,而是:

  • 有明确需求对象
  • 不走库存缓冲
  • 由下游需求直接拉起上游补给

在制造场景里,这通常意味着 MO 更强地带着销售 / 下游 move 语义。

Orderpoint:需求来自库存目标

Orderpoint 的核心则是:

  • 为了把库存补到目标区间
  • 需求不是某张具体订单一对一拉起
  • 更偏预测、库存政策和计划补货

所以两者都可能走 Manufacture route,但心智模型完全不同:

  • MTO:谁要,我给谁做
  • Orderpoint:库存缺了,我先补到位

为什么 scheduler 不一定立刻给你最终状态

stock_orderpoint._post_process_scheduler() 里有一个很重要的设计:

先让所有 orderpoint 跑完 procurement,再统一把对应 draft MO 确认为 confirmed。

这样做是为了避免:

  • 某张刚确认的 MO 又立刻触发新的补货冲突
  • 多条补货规则互相抢上下文

所以你看到 scheduler 跑完后某些 MO 的确认时机不是瞬时同步,其实正是官方在避免补货链互相打架。


新手最容易踩的 5 个坑

坑 1:以为开了 Manufacture route 就万事大吉

不够。

没有正常 BOM,或者 BOM 选择上下文不对,Manufacture route 也只会把问题更快暴露出来。

坑 2:忽略 orderpoint 上的 BOM 指定

多 BOM 产品下,不显式指定 BOM,经常会导致“补货规则页面想要 A,系统最后制造成 B”。

坑 3:把 phantom kit 和制造补货混用

源码里明确限制:phantom kit 产品不能再配 reordering rule。

因为 kit 的语义是展开,不是制造入库。

坑 4:只看 produce_delay,不看 days_to_prepare_mo

很多团队只看制造提前期,却忘了组件供应提前期也会被 BOM 带进计划链。

坑 5:自定义时把 orderpoint_idbom_id 覆盖掉

这类 bug 特别隐蔽。

表面看 MO 建出来了,实际上上下文丢了,后续补货通知、BOM 追溯和复用已有 MO 的逻辑都会失真。


开发时最该注意什么

1. 保住 procurement 上下文

最重要的不是“我也能建 MO”,而是你自定义后:

  • bom_id
  • orderpoint_id
  • reference_ids
  • move_dest_ids

有没有被正确保留。

2. 多 BOM 产品一定要测默认路径和显式路径

至少要测两类:

  • 没指定 BOM 时系统怎么选
  • 指定 BOM 时是否真能贯穿到最终 MO

3. 调 lead time 时别只改一层

制造计划日期不仅受 produce_delay 影响,还受:

  • rules delay
  • 非单步制造下的 pre-production 规则
  • days_to_prepare_mo

共同影响。

4. 看补货链时不要只盯 MO

还要同时看:

  • orderpoint
  • stock rule
  • 下游 move / reference
  • scheduler 后处理

这样你才能分清这张单到底是“订单拉的”,还是“库存补的”。


最后总结

制造补货的核心,不是谁会创建 MO,而是谁把需求语义、BOM 选择和计划时间带进了 MO。

在 Odoo 里:

  • Orderpoint 负责把“库存政策”变成制造上下文
  • MTO 负责把“具体需求”变成拉动信号
  • Manufacture route 负责把这些信号落成制造单

真正理解这三层,你才不会把所有“自动建 MO”都看成同一种机制。

DISCUSSION

评论区

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