耗材收货

Odoo 耗材采购为什么有时按库存 move 算收货:purchase_stock 对 qty_received_method 的改写边界讲透

很多人记得采购里服务/耗材常是手工收货数量,但一装上 purchase_stock,耗材采购的 qty_received_method 其实会被改成 stock_moves。本文把这条经常被忽略的边界讲透。

采购
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

如果你只看基础 purchase 模块,很容易形成一个印象:

  • 服务和耗材采购的 qty_received_method 多半是 manual

但在 /home/ubuntu/odoo-temp/addons/purchase_stock/models/purchase_order_line.py 里,purchase_stock 明确把耗材产品的逻辑改了:

  • product_id.type == 'consu' 的采购行
  • qty_received_method = 'stock_moves'

这意味着:

安装 purchase_stock 之后,耗材采购不再只是手工维护已收数量,而会重新挂回库存 move 驱动。

这正是很多项目里“同样是耗材,为什么这个库手工改不了 qty_received,那个库却能改”的根因。


为什么这条边界容易被误读

因为很多人记住的是“服务/耗材不是可库存产品,所以通常不走库存收货”。

这个印象在基础采购模块下并不算错。

purchase_stock 的立场更偏业务执行:

  • 只要耗材采购已经纳入库存收货链
  • 那已收数量就应该尽量由 move 事实驱动

这和“产品是否永久进库存估值”不是同一个问题。

也就是说,Odoo 在这里区分的是:

  • 是否需要库存动作来表达收货事实
  • 而不是简单按“是否 storable”一刀切

这带来的最大变化:qty_received 不再只是用户输入框

当耗材行走 stock_moves 后,源码会通过 _prepare_qty_received() 汇总相关 move,计算已收数量。

而且处理得并不粗糙,它会细分:

  • 正常完成的收货 move → 加数量
  • 采购退货且应退款 → 减数量
  • 某些 dropship return 边界场景 → 避免重复计数
  • 某些 purchase return 的回流场景 → 也有跳过条件

这说明 Odoo 在这里不是“简单把 move 数量相加”,而是在尽量让 qty_received 贴近真实业务含义。


为什么退货和代发回流会让人看不懂数量

源码里最值钱的部分,恰恰是那些 elif 分支。

它们表达的是:

  • 并不是所有 done move 都应当计入“本次采购已收”
  • 有些 move 是退货链的一部分
  • 有些是 dropship 的回流边界
  • 有些虽然是 done,但如果直接累加会把已收数量算重

这就是为什么现场里常见的抱怨:

  • “收货都 done 了,为什么 qty_received 不是我以为的数?”

根因不在字段坏了,而在于 Odoo 正在尝试区分:

  • 收到
  • 退回
  • 回流但不应重记

这些语义并不一样。


另一个容易忽略的影响:改数量会反过来动库存动作

purchase_stock 里采购行的 write()create()_create_or_update_picking() 也都围绕耗材做了处理。

这意味着:

  • 你增减采购行数量
  • 不只是 PO 行数字变了
  • 相关 picking / move 也可能被创建、补齐、重算

所以在这个模块下,耗材采购已经不是“轻量采购记录”,而是和库存执行真正连起来了。


最容易误解的 5 个点

1. 以为耗材采购永远是 manual received

安装 purchase_stock 后,不成立。

2. 以为只有 storable 产品才会由 move 驱动已收数量

耗材在这里就是例外。

3. 以为 done move 全都应当直接累计

退货与回流场景有排除逻辑。

4. 以为 qty_received 不对就是界面字段问题

通常要先看 move 链和 return 语义。

5. 以为改采购行数量只是改采购

它还可能触发 picking / move 更新。


排错顺序

如果你遇到耗材采购已收数量“不对”,建议按这个顺序查:

  1. 是否安装并走到了 purchase_stock 逻辑
  2. 该产品类型是否为 consu
  3. 采购行当前 qty_received_methodmanual 还是 stock_moves
  4. 关联 move_ids 哪些是 done、哪些是 return
  5. 是否存在 dropship return 或 purchase return 回流边界
  6. 最近是否改过采购数量,导致 picking/move 被重建或重算

一句话记忆法

在 Odoo 的 purchase_stock 世界里,耗材采购不再只是手工记“收了多少”,而是尽量让库存 move 事实来回答这个问题。

DISCUSSION

评论区

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