先说结论
采购单确认之后,Odoo 做的并不只是“生成一张收货单”。
更准确地说,它会完成三件事:
- 把采购承诺正式落地
- 把每条采购需求翻译成库存移动任务
- 把这些任务归并进可执行的收货单据里
所以你在界面里看到的“收货单出来了”,背后其实不是采购模块单独把一切都做完,而是采购模块把需求交给库存模型继续推进。
入口: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
评论区