供给方式

Odoo 里 make_to_stock、make_to_order、mts_else_mto 到底怎么影响链路:procure_method 深度解读

很多人知道 Odoo 有 MTS、MTO、MTS else MTO,但总把它们和 route 混在一起。本文从源码里的 procure_method 出发,讲清三种供给方式到底分别意味着什么、为什么会改变 move 状态与补货传播、以及 mts_else_mto 为什么最容易让人误判。

Odoo 开发 库存
进阶 开发者 3 分钟阅读
0 评论 0 点赞 0 收藏 31 阅读

先说结论

如果你已经理解了 route 决定方向、rule 决定动作,那接下来最容易把人绕进去的,就是 procure_method

最实用的理解是:

procure_method 决定这一步需求是优先吃当前来源位置的库存,还是继续把需求往上游传。

三种模式可以先粗暴记成:

  • make_to_stock:先当成“从现货里满足”
  • make_to_order:不要先吃现货,直接继续往上游触发规则
  • mts_else_mto:能吃现货先吃,不够的那部分再继续往上游传

所以它不是 route 的同义词,也不是采购/制造的别名。

它更像:

当前这一步供应动作采用什么供给策略。

这就是为什么同一条 route、同一条 rule,换个 procure_method,后面的 move 状态、procurement 传播、补货结果都可能变掉。


为什么很多人会把它和 route 混在一起

因为 UI 上更显眼的通常是 route。

比如你更容易先看到:

  • Buy
  • Manufacture
  • Replenish on Order
  • Dropship

procure_method 往往藏在 rule 细节里,不像路线那样一眼可见。

于是就容易产生一个误解:

  • 只要路线选好了,系统自然知道该怎么补

其实不够。

因为 route 解决的是:

  • 这条需求允许走哪种履约方向

procure_method 解决的是:

  • 在当前这一步,来源位置是优先直接供货,还是继续往更上游再找供应

所以前者更像“选路”,后者更像“这一步怎么供”。


先看 Odoo 官方源码对三种模式的原始定义

addons/stock/models/stock_rule.py 里,stock.rule.procure_method 的定义就是:

  • make_to_stockTake From Stock
  • make_to_orderTrigger Another Rule
  • mts_else_mtoTake From Stock, if unavailable, Trigger Another Rule

这个定义其实已经很直白了。

make_to_stock

官方语义就是:

从当前来源位置的可用库存里拿。

make_to_order

官方语义就是:

不看当前来源位置有没有货,直接继续触发另一条规则,把货补到这里来。

mts_else_mto

官方语义就是:

能从当前来源位置拿就先拿,不够的缺口再继续触发下一层规则。

你会发现,三者真正的分界不是“是不是采购”或者“是不是制造”,而是:

  • 当前来源位置的库存要不要优先参与这一步 fulfilment

为什么这三个选项本质上是在回答同一个问题

你可以把它们都理解成在回答这句:

“下游需要的货,当前来源位置要怎么供?”

三个答案分别是:

答案 1:make_to_stock

先直接从当前来源位置供。

答案 2:make_to_order

当前来源位置先别谈现货,直接让更上游去准备。

答案 3:mts_else_mto

当前来源位置能供多少先供多少,不足的那部分再往上游追。

一旦这样理解,你就不会再把它们误当成“采购模式”“制造模式”或者“路线名称的另一个写法”。


make_to_stock 到底在做什么

make_to_stock 最像的业务语义是:

当前来源位置被当成这一步的直接供货点。

也就是说,系统在这一步不会优先再往上游派生新的 procurement,而是先把 move 当成“从这里出货”的动作。

这不等于“仓里一定真的有足够库存”

这里很多人会误解。

make_to_stock 的意思不是:

  • 系统一定验证这里货够
  • 不够就立刻自动处理所有上游问题

它更准确地表示:

  • 这一步 move 的供给语义是 from stock

后面能不能立刻 assign、会不会 waiting、是否触发其他补货机制,还要看 reservation、scheduler、orderpoint、可用量等其他机制。

所以 make_to_stock 不是“保证现货足够”,而是“先按库存供给语义来处理”。


make_to_order 到底在做什么

make_to_order 的核心不是“采购”,也不是“制造”。

它真正表达的是:

这一步不要先假定来源位置直接供货,而是继续创建 procurement,让系统再往上游找 rule。

这点在 stock.move._action_confirm() 里体现得非常明显。

源码里,如果 move 是 make_to_order

  • move 会进入 waiting
  • 同时会加入 move_create_proc
  • 然后系统调用 stock.rule.run(procurement_requests)

翻成人话就是:

这张 move 自己先别当最终供货者,它在确认时会继续把“我要货”这件事往上游再发一次。

这就是为什么 MTO 看起来像“会自己长链条”。

其实不是魔法,而是:

  • move confirm 时又触发了一层 procurement
  • 新 procurement 再去命中新一条 rule
  • 新 rule 再决定是 pull / buy / manufacture / 其他动作

所以 make_to_order 真正强调的是:

  • 需求继续传播

而不是某一种具体业务单据类型。


mts_else_mto 为什么最容易被误解

因为它是三者里最像真实业务、也最不像“一刀切”的那个。

它表达的是:

当前来源位置的库存不是完全不看,也不是绝对优先;系统会先吃可用量,再只为缺口继续派生 procurement。

这比纯 MTS 和纯 MTO 都更接近很多企业的真实需求。

例如:

  • 仓里有 6 个
  • 客户要 10 个

那业务上很多人想要的其实是:

  • 先把 6 个现货吃掉
  • 剩下 4 个再去补

而不是:

  • 要么完全从库存拿
  • 要么 10 个全部重新补

mts_else_mto 正是干这个的。


源码里 mts_else_mto 是怎么落地的

这一段非常关键。

很多人以为 mts_else_mto 会在一开始就生成一种“半库存、半补货”的神奇 move。

源码不是这么做的。

第一步:在 _run_pull() 里先把 move 当成 make_to_stock

stock_rule._run_pull() 里,Odoo 会先做一个转换:

  • 如果 rule 的 procure_method == 'mts_else_mto'
  • 那生成 move values 时,先把 move 的 procure_method 写成 make_to_stock

这一步很有意思。

它意味着:

Odoo 先把这一步 move 落成“库存供给语义”的 move。

也就是说,落 move 这件事本身不会直接写成一半 MTO。

第二步:在 stock.move._action_confirm() 里单独把它识别出来

源码里又有一段专门逻辑:

  • 如果 move 的 rule_id.procure_method == 'mts_else_mto'
  • 那这个 move 既会进入 confirmed
  • 也会加入 move_create_proc

这说明 Odoo 的思路不是“二选一”,而是:

  • move 先按库存方向成立
  • 同时再根据缺口继续创建 procurement

第三步:真正继续往上游补多少,靠 _prepare_procurement_qty()

这一步最值钱。

源码里会按 location + product 读取 free_qty,然后只为缺口部分生成 procurement 数量。

也就是说,系统不是傻傻地把整张需求再重新补一次,而是大致按这个逻辑:

  • 缺口 = max(需求量 - 可用量, 0)

然后只为这个缺口继续触发上游 rule。

这就是 mts_else_mto 最关键的本质:

当前层先保留库存 fulfilment 语义,但补货传播只针对“不够的那部分”。


为什么 mts_else_mto 看起来总让人觉得“系统行为怪怪的”

因为它天然就是混合模式。

混合模式最容易带来三种错觉。

错觉 1:为什么 move 已经 confirmed 了,系统还在继续补货

因为这是它本来就该干的事。

  • move 作为库存供给动作已经成立
  • 但缺口还要继续往上游追

错觉 2:为什么有些数量像吃了库存,有些数量又像重新采购/制造了

因为这正是 mts_else_mto 的目标。

  • 可用量部分走本地库存
  • 缺口部分走上游 replenishment

错觉 3:为什么我看单据时总觉得来源不统一

因为它本来就是“同一步需求拆成两个供给来源”的策略。

如果你脑子里只有“全库存”或“全补货”两种模型,就很难读懂它。


三者真正的差异,不在名字,而在 move confirm 时怎么传播需求

如果你只用业务术语理解,会觉得它们像配置项。

如果你看源码,会发现真正的差异点在:

  • move _action_confirm() 时,系统要不要继续创建 procurement,以及创建多少。

你可以这样记:

make_to_stock

  • 当前 move 主要按库存供给处理
  • 不会因为这个 procure_method 自己继续派生 procurement

make_to_order

  • 当前 move 会进入 waiting
  • 会继续派生 procurement
  • 需求会被完整继续往上游传播

mts_else_mto

  • 当前 move 先按库存方向存在
  • 同时会继续派生 procurement
  • 但只为缺口数量继续传播

这才是三者最核心的差异。


用一个最简单的数量例子讲透

假设下游要 10 个,当前来源位置可用量是 6 个。

如果是 make_to_stock

系统更偏向:

  • 这 10 个需求先按“从这里供货”理解
  • 至于能不能马上全保留 / assign / 后续怎么补,是别的机制的问题

如果是 make_to_order

系统更偏向:

  • 这 10 个不要先假定来源位置自己供
  • 直接把 10 个需求往上游继续发

如果是 mts_else_mto

系统更偏向:

  • 当前层先保留 from stock 语义
  • 只把缺的 4 个往上游继续发

所以业务上最常见的感觉会是:

  • MTS:像本仓负责
  • MTO:像上游负责
  • MTSO:像本仓先负责一部分,剩下的再交给上游

这样就直观多了。


为什么它会直接影响采购、制造和调拨结果

因为采购、制造、内部调拨这些“动作类型”通常是 rule action 决定的;但需求会不会传到能命中这些 action 的上游规则那里,又取决于 procure_method

换句话说:

  • route / rule action 决定“上游如果被触发,会做什么”
  • procure_method 决定“要不要把需求继续传到那个上游去”

所以很多人说:

  • 为什么同样是买这条 route,有时直接动本仓库存,有时又去采购?

本质上常常不是 route 名字的问题,而是:

  • 当前节点是 MTS 还是 MTO / MTSO

实战里最容易踩的 7 个坑

1. 把 MTO 理解成“采购模式”

错。它只是“继续触发上游规则”,上游可以是采购,也可以是制造,也可以是另一次 pull。

2. 把 MTS 理解成“库存一定够”

错。它只是当前步骤采用库存供给语义,不等于系统保证足量现货。

3. 低估 mts_else_mto 的复杂度

它最接近真实业务,但也最容易造成“为什么一部分这样、一部分那样”的错觉。

4. 只看 rule action,不看 procure_method

你会解释不了为什么同一 action 有时不继续补货、有时继续补。

5. 只看 move 创建,不看 move confirm

三者真正分叉常发生在 _action_confirm()

6. 调试时不看 _prepare_procurement_qty()

尤其是 mts_else_mto,缺口数量到底怎么算,这里才是关键。

7. 以为 route、rule、procure_method 三者是重复字段

不是。它们分工完全不同:

  • route:路径选择范围
  • rule action:这一步做什么动作
  • procure_method:当前来源层怎么供

最实用的调试顺序

如果你想快速看懂一条库存链为什么这样跑,我建议按这个顺序:

  1. 先看命中的 rule 是哪条
  2. 再看它的 action 是什么
  3. 再看它的 procure_method 是什么
  4. 再看 move confirm 后有没有继续派生 procurement
  5. 如果是 mts_else_mto,重点看缺口数量是怎么算出来的

这比一上来只盯采购单、制造单、拣货单更快抓根因。


一句话记忆法

把三者记成一句话:

make_to_stock 是“这一步先按库存供”,make_to_order 是“这一步继续把需求往上游传”,mts_else_mto 是“能从库存供的先供,不够的那部分再往上游传”。

理解这一句之后,你再看 Odoo 的库存、补货、采购、制造链路,就不会只停留在“路线名字像懂了”,而会真正看懂需求是怎么在每一层被供给、被传播、被拆分的。

DISCUSSION

评论区

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