状态机排查

Odoo 库存 move 状态机怎么读:waiting、confirmed、partially_available、assigned 排查顺序讲透

很多人看到 Odoo 库存 move 的 waiting、confirmed、partially_available、assigned 这些状态,只会凭经验猜“是不是没货”“是不是没分配”。本文直接从源码里的状态写入逻辑出发,讲清每个状态到底在表达什么、状态是怎么切出来的,以及排查时该先看什么。

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

先说结论

如果你排查 Odoo 库存链路时总盯着单据状态发呆,那很容易越看越乱。

最实用的理解是:

stock.move 的状态不是“系统心情”,而是在表达这张 move 当前卡在哪一层:前置依赖、可分配性、还是已完成预留。

你可以先把几个常见状态记成这样:

  • waiting:我前面还有依赖,先等
  • confirmed:我已成立,但还没真正拿到货
  • partially_available:我拿到了一部分,不是全部
  • assigned:我需要的量已经完成预留

所以状态机的重点不是背单词,而是看:

  • 它为什么会进入这个状态
  • 从这个状态跳到下一个状态的条件是什么

这才是排查真正有用的部分。


为什么很多人会把库存状态看成“玄学”

因为前台看到的只是一个词:

  • Waiting
  • Ready
  • Partially Available

但源码里不是按“显示词”来思考的,而是按一系列条件判断:

  • 有没有前置 move
  • procure_method 是什么
  • 有没有 reserve 到足够 quantity
  • reservation_date 到没到
  • 当前 quant / move line 情况怎么样

所以你在 UI 里看到的是一个状态名,源码里真正表达的是:

这张 move 目前属于哪一类可执行性。

只要脑子里换成“可执行性分类”而不是“状态标签”,理解就会顺很多。


第一层:waiting 到底是在等什么

很多人一看到 waiting,第一反应就是:

  • 没货了

其实不一定。

stock.move._action_confirm() 里,源码很清楚:

  • 如果 move 有 move_orig_ids
  • 那它会先进入 waiting

翻成人话就是:

只要这张 move 有前置依赖,它就不是链路第一跳,所以先等前面的 move。

这很关键。

因为这说明 waiting 首先表达的不是“库存数量不足”,而是:

  • 供应链顺序上,我还没轮到。

还有一种 waiting

源码里还有一类:

  • 如果 move 是 make_to_order
  • 它也会进入 waiting

原因是:

  • 当前这张 move 不是直接从现货完成
  • 它还要继续向上游触发 procurement

所以 waiting 本质上通常来自两类原因:

  1. 有前置 move
  2. 需要继续等上游补货动作长出来

第二层:confirmed 到底在表达什么

confirmed 最容易被误读成:

  • 已经差不多好了

其实更准确的理解是:

这张 move 在业务上已经成立,但当前还没拿到足够的预留结果。

也就是说:

  • 不是 draft 了
  • 也不是纯等待前置链了
  • 但还没进入“我已经拿到货”的状态

_action_confirm() 里,普通 move 往往会被写成 confirmed

后面如果满足条件,系统才会进一步 _action_assign()

所以 confirmed 更像:

  • 已进入执行队列,但资源还没真正锁到手

这跟很多人以为的“马上就 ready”其实差一层。


第三层:partially_available 为什么特别值钱

这个状态常常被忽略,但它在实战里很值钱。

它表示:

这张 move 不是完全没拿到货,而是已经 reserve 到了一部分。

这通常意味着:

  • 数量边界不够整张吃满
  • 一部分库存已经可用
  • 剩下部分还在等进一步供给或后续操作

_action_assign() 以及后续状态整理逻辑里,源码都会单独把它和 assigned 分开。

这很重要,因为 partially_available 告诉你:

  • 问题不是“完全没有库存”
  • 而是“库存 / 可分配量 / 时机 / 上游链路只够一部分”

所以一张 move 如果长期停在 partially_available,排查思路就不该再是“为什么一点都没分到”,而应该转成:

  • 差的那部分为什么一直补不上

第四层:assigned 真正表示什么

assigned 才是大家最想看到的状态。

它表示:

需要的 quantity 已经完成 reservation,可以进入后续作业。

但这也不等于“业务流程已经结束”,只是表示:

  • 这张 move 在库存占用层已经准备好了

所以你可以把它理解成:

  • 货已经真正锁住了
  • 仓库可以开始按这张 move 干活

这也是为什么很多 picking 到了 assigned,用户体感上就觉得“终于 ready 了”。


源码里真正的状态切分点在哪里

最值钱的一段在 stock.move 里整理状态的逻辑,大意可以翻成这样:

进入 assigned

  • 当前已 reserve 数量 >= 需求数量

进入 partially_available

  • 当前 reserve 到了一部分
  • 但还没达到全部需求

进入 waiting

  • 是 MTO 且没有前置来源,或者
  • move_orig_ids 且前置里仍有未完成的正向 move

否则进入 confirmed

  • 已成立,但既不是明确等待依赖,也还没 reserve 到任何 / 足够数量

这段逻辑很值钱,因为它让你知道:

状态不是凭感觉切的,而是按“依赖 + reservation 结果”算出来的。


为什么 reservation_date 会改变状态体感

这点很多人会忽略。

move 不是一 confirmed 就一定立刻 assign。

源码里的 _should_assign_at_confirm() 条件大致是:

  • bypass reservation,或者
  • picking type 的 reservation_method == at_confirm,或者
  • reservation_date <= 今天

这意味着:

有些 move 之所以一直停在 confirmed,不是因为系统不行,而是因为它还没到该抢库存的时间。

所以当你看到:

  • move 已 confirmed
  • 也没有 waiting 的前置依赖
  • 但迟迟没进 assigned / partially_available

一定要查:

  • reservation method
  • reservation_date

否则你会误判成库存问题。


一个非常实用的状态机理解法

你可以把 move 状态机先粗暴拆成三层:

第一类:顺序问题

  • waiting

说明:

  • 我前面还有链路没走完

第二类:资源问题

  • confirmed
  • partially_available
  • assigned

说明:

  • 链路上轮到我了,但资源锁定程度不同

第三类:完成 / 取消问题

  • done
  • cancel

说明:

  • 这张 move 已经离开当前执行竞争

这样一来,你排查时就不会把所有状态都当一个维度看。


最实用的排查顺序

如果你想快速看懂一张 move 为什么停在当前状态,我建议按这个顺序:

1. 先看它是不是 waiting

如果是,先查:

  • move_orig_ids
  • 上游 move 状态
  • 是否是 MTO 链的一环

2. 如果不是 waiting,而是 confirmed

查:

  • reservation_method
  • reservation_date
  • 有没有真正触发 _action_assign()

3. 如果是 partially_available

查:

  • 已 reserve 数量 vs 目标数量
  • 缺的那部分为什么补不上
  • 有没有 lot / owner / package / tracking 边界

4. 如果是 assigned

说明 reservation 层已经过了,后面要看的是:

  • 仓库执行
  • move line
  • validate / done 过程

这套顺序会比“先看库存够不够”更稳。


最容易踩的 6 个坑

1. 把 waiting 简化成“没货”

很多时候它是在等前置 move,不是在等凭空长库存。

2. 把 confirmed 误以为“马上就 ready”

它只是进入执行队列,不代表已经 reserve 到货。

3. 把 partially_available 当成“几乎等于 assigned”

不是。它说明还有缺口,只是缺口不是 100%。

4. 忽略 reservation timing

有些 move 还没到 reservation_date,本来就不会立刻分配。

5. 只看当前 move,不看上游链

特别是 waiting 场景,单看当前 move 基本看不明白。

6. 只看状态,不看数量

assigned / partially_available 的分界,本质上就是数量比较。


一句话记忆法

把 move 状态机记成一句话:

waiting 是顺序还没轮到,confirmed 是业务已成立但资源未锁定,partially_available 是锁到一部分,assigned 是锁到全部。

理解这一句之后,你再看 Odoo 库存 move 的状态,就不会再把它们当成抽象标签,而会开始看到:

  • 这张 move 是卡在依赖
  • 还是卡在时机
  • 还是卡在数量
  • 还是已经真的 ready 了

DISCUSSION

评论区

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