采购到收货链

Odoo 采购确认后,收货单和补货链是怎样被串起来的

从 purchase.order.button_confirm 到 stock.move / picking 创建,讲清楚 Odoo 采购单确认后,收货、入库和后续库存流转是如何被源码连接起来的。

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

先说结论

采购单确认之后,Odoo 做的并不只是“生成一张收货单”。

更准确地说,它会完成三件事:

  1. 把采购承诺正式落地
  2. 把每条采购需求翻译成库存移动任务
  3. 把这些任务归并进可执行的收货单据里

所以你在界面里看到的“收货单出来了”,背后其实不是采购模块单独把一切都做完,而是采购模块把需求交给库存模型继续推进。


入口:purchase.order.button_confirm()

采购确认的入口在采购订单本身。

你点“确认订单”时,业务上发生的是:

  • 供应商采购承诺成立
  • 每条采购行进入后续履约流程
  • 系统开始准备对应的入库动作

这里最值得记住的一点是:

采购单头负责确认业务,真正生成库存动作的关键数据大多在采购行上。

因为同一张采购单里的不同产品,可能有不同的收货路线、目的地库位、提前期甚至公司上下文。


核心对象:采购行不是“明细”,而是履约任务源头

很多人把 purchase.order.line 当成一条普通明细。

其实在收货链路里,它更像“待执行需求”。

每条采购行至少定义了这些关键事实:

  • 买什么产品
  • 买多少
  • 什么时候期望到货
  • 属于哪个公司
  • 将来要落到哪个库存位置

这些信息最终会被翻译进 stock.move

也就是说:

采购行是业务表达,库存 move 是执行表达。


为什么采购确认后通常会生成 stock.picking

在 Odoo 的库存体系里,真正承载“这批货要被收进来”的不是采购单,而是:

  • stock.move:具体移动任务
  • stock.picking:把多条 move 组织成一张可执行单据

所以采购确认后最常见的链路其实是:

purchase.order
  -> purchase.order.line
  -> stock.move
  -> stock.picking (incoming)

这也是为什么采购人员最终操作收货时,通常是在收货单里验收入库,而不是回到采购单里直接“做库存”。


stock.move 在这里到底代表什么

很多人第一次学 Odoo,会把 move 理解成“已经移动完成”。

其实不是。

stock.move 更像是一条应当发生的库存流转声明

在采购场景里,它通常表达的是:

  • 从供应商位置
  • 移动到仓库的入库位置或中转位置
  • 数量是多少
  • 关联哪条采购行

所以 move 不是“结果”,而是“待执行/执行中的流转任务”。

这个理解非常重要,不然后面你就会把:

  • move
  • move line
  • picking
  • 库存数量变化

全部混在一起。


为什么有时是一张收货单,有时会拆成多张

这和 picking 归并规则有关。

Odoo 不会无脑把所有采购行塞进同一张 picking,而是会看一组归并维度,比如:

  • 供应商
  • picking type
  • 公司
  • 目的位置
  • 调度时间窗口

如果这些关键上下文一致,多条 move 往往会进入同一张 incoming picking。

如果不一致,就可能拆成多张。

所以“为什么同一个 PO 没有只生成一张收货单”通常不是 bug,而是上下文不够一致。


收货不是采购模块单独完成的

这点特别值得记。

采购模块负责提出“我买了这些东西”。

但真正让货物进入库存状态变化的,是库存模块后面的动作,比如:

  • picking confirm
  • reservation / assign
  • 收货时填写 move line
  • validate 后更新 quants

所以如果采购单正常确认了,但仓库侧看起来不对,不要只查 purchase。

你还应该继续看:

  • 对应 move 是否创建
  • picking 是否在正确状态
  • 目标库位是否合理
  • 验收入库时 move line 是否正确生成

采购数量、到货数量、入库完成数量为什么经常不一样

因为它们属于不同层次。

可以这样记:

  • 采购行数量:你向供应商下了多少
  • move 需求数量:系统计划收多少
  • move line 实际数量:仓库这次实际收了多少

当出现分批到货、少货、多货、补货时,这三个数字就不一定相同。

这不是系统乱,而是 Odoo 故意把“计划”和“执行”拆开了。

也正因为这样,它才能支持现实世界里的复杂收货场景。


实战里最容易误解的点

1. 采购确认 ≠ 库存已经入账

确认采购单通常只是把履约链启动。

真正库存增加,要等收货单验证完成。

2. 收货单不是采购单的附件,而是库存执行对象

很多业务用户觉得收货单只是采购单的“附带页面”。

从技术上看,它其实是独立的库存对象。

3. stock.move 不等于明细行录入

真正记录本次收了哪一批、哪一包、哪个 lot/serial 的,更多是在 move line 层。

4. 问题不一定在采购模块

收货异常经常可能出在:

  • 仓库配置
  • 入库类型
  • 目的位置
  • 多公司上下文
  • 路线配置

一套很实用的排查顺序

如果你遇到“采购确认后没生成收货单”或“收货链不对”,建议按这个顺序查:

1. 看采购单状态是否真的 confirmed

先排除流程没走到。

2. 看采购行对应的 move 是否已生成

如果 move 都没有,问题通常还在采购到库存的转换阶段。

3. 看 picking type 和目标仓库配置

很多异常来自仓库配置,而不是源码逻辑本身。

4. 看 incoming picking 是否被归并/拆分

别被“为什么不是一张单”误导。

5. 看收货验证时 move line 是否完整

尤其是 lot/serial、包装、部分收货场景。

6. 看库存数量变化是否发生在 validate 之后

不要把确认采购单和实际入库混为一谈。


一句话记忆法

把整条链记成一句话:

采购模块负责表达“我要买”,库存模块负责把“买到的货如何真正收进仓库”执行出来。

掌握这句,采购到收货这条链路就不容易看乱。

DISCUSSION

评论区

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