库存过账链路

stock.move 的预留与过账:_action_assign 到 _action_done 的全过程

从 stock.move._action_assign、_update_reserved_quantity 到 _action_done 和 _create_backorder,理解 Odoo 库存是怎样从“可用”变成“已完成”的。

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

先说结论

stock.move 是 Odoo 库存链路里最核心的“执行单元”。

很多人只看到界面上的状态变化:

  • Waiting
  • Available
  • Assigned
  • Done

但源码里真正发生的事情更像一条流水线:

  1. 先判断这张 move 要不要预留
  2. 再把可用库存写成 move line
  3. 如果数量不够,就标成部分可用
  4. 到了过账时,再把 move line 逐条落地
  5. 如果只做了一部分,就拆 backorder
  6. 最后把下游 move 继续推下去

所以,stock.move 不是“一个状态字段”,而是 库存执行过程本身


_action_assign() 做的不是“改状态”,而是“算预留”

addons/stock/models/stock_move.py 里,_action_assign() 的注释已经说明了核心目标:

Reserve stock moves by creating their stock move lines.

也就是说,它不是简单把 move 改成 assigned,而是:

  • 根据需求数量找可用 quants
  • 创建或更新 stock.move.line
  • 让预留数量和需求数量对齐

源码里先会区分:

  • 已经满足的 move
  • 需要部分预留的 move
  • 需要直接跳过预留的 move

这一步很关键,因为后面的所有状态,其实都来自 move line 的预留结果,不是反过来。


为什么会出现 partially_available

如果可用库存不够,Odoo 不会硬把它当成失败,而是进入 partially_available

这正是库存链路很实用的地方:

  • 有多少,就先占住多少
  • 剩下的差额继续留在需求里
  • 等后续补货、到货或别的链路补齐

你可以把它理解为:

系统不是在问“能不能一次做完”,而是在问“现在能先推进多少”。

这也是为什么 Odoo 的库存状态看起来不像传统 ERP 那样二选一,而是很细腻。


_update_reserved_quantity() 负责把“可用量”写进 move line

真正创建预留行的动作,落在 _update_reserved_quantity()_update_reserved_quantity_vals()

这两个方法会做几件事:

  • 先从 stock.quant 里查可预留数量
  • 按批次、包裹、所有人、库位分组
  • 尽量复用已有 move line
  • 不够时再新建 move line

这里有一个很重要的设计点:

Odoo 预留的不是抽象数字,而是具体到 location / lot / package / owner 的库存片段。

所以你在界面里看到的“已预留 5”,背后往往不是一个值,而是几条有明确来源的 move line。


_action_done() 才是真正的“落地完成”

_action_assign() 只是预留,真正把库存变化写死的是 _action_done()

这一步会先处理几个问题:

  • 草稿 move 会被先确认
  • 没有勾选或数量为 0 的 line 会被清理
  • 必要时先创建 backorder
  • 然后再对 move line 调 _action_done()

接着它会:

  1. 把 move 标记成 done
  2. 写入完成时间
  3. 推动下游 move 重新 _action_assign()
  4. 必要时继续生成新的 backorder

所以“点了验证”不是一个动作,而是 完成、推送、重算、拆单 的组合。


新手最容易误解的 3 件事

1)Assigned 不等于已经出库

Assigned 只表示预留好了,不代表库存已经真的减少。

2)Done 不是结束,而是链路的中间点

对于有下游 move 的场景,当前 move done 后,后面的 move 才有机会继续被推进。

3)backorder 不是异常,而是正常拆分机制

只做了一部分时,Odoo 倾向于把未完成部分保留下来,而不是直接报错中断。


实战开发时的建议

如果你要扩展库存逻辑,优先考虑这几个原则:

  • 尽量用 hook,而不是整段重写 _action_assign() / _action_done()
  • 不要假设数量字段就代表真实预留结果
  • 处理多公司、多批次、包装和追溯时,一定要考虑 move line 维度
  • 需要调试时,先看 move state,再看 move line,再看 quant

理解了这条链路,你就能看懂很多库存“为什么没按我想的来”的问题。

DISCUSSION

评论区

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