销售到库存分流

销售确认后,Odoo 为什么先跑 procurement,再决定发货还是补货

从 sale.order._action_confirm 到 sale.order.line._action_launch_stock_rule,再到 stock.rule.run,讲清楚销售需求如何分流成发货、采购或制造。

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

先说结论

Odoo 的销售确认,并不是“点一下按钮就直接生成发货单”。

更准确地说,它先把销售需求交给 procurement,再由库存规则决定下一步是:

  1. 直接拉出库动作
  2. 生成采购需求
  3. 触发制造需求

这就是为什么同样是“确认销售单”,不同产品、不同路线、不同仓库下,结果会完全不一样。


入口:sale.order._action_confirm()

sale_stock/models/sale_order.py 里,确认逻辑最醒目的代码只有一行:

self.order_line._action_launch_stock_rule()

这句话的意思很清楚:

  • 订单头负责把业务状态推进到“已确认”
  • 订单行负责把“这份需求怎么履行”传给库存规则

也就是说,真正决定后续路径的不是销售单头,而是每一条明细行的产品、路线、仓库、交货位置和数量


真正的起点:sale.order.line._action_launch_stock_rule()

这一步是整条链路的核心。

代码会先过滤掉不该进入库存链路的行,比如:

  • 状态还不是 sale
  • 订单被锁定
  • 已经处理过同样数量,不需要重复跑
  • 还有上下文里显式要求跳过 procurement 的情况

然后它会计算“还差多少没被履约”:

qty = line._get_qty_procurement(previous_product_uom_qty)
if float_compare(qty, line.product_uom_qty, precision_digits=precision) == 0:
    continue

这段逻辑很重要,因为 Odoo 不是每次都重新造一套单据,而是先看:

这条销售行,是不是已经有足够的下游动作覆盖了?

如果已经覆盖,就不再重复创建。


procurement 里装了什么

接下来,销售行会准备 procurement values,再组装成 stock.rule.Procurement

procurements += line._create_procurements(product_qty, procurement_uom, values)

你可以把 procurement 理解成一个“需求包”。

它不直接告诉系统“去建哪个对象”,而是带着这些信息:

  • 产品是什么
  • 要多少
  • 用什么计量单位
  • 送到哪里
  • 来源单据是谁
  • 关联哪些参考对象

这就是 Odoo 设计得很聪明的地方:

销售只描述需求,不决定实现方式。


谁来决定“发货、采购还是制造”

最后是 stock.rule.run(procurements)

这一步才真正把需求分流成不同执行路径:

  • _run_pull:走拉式库存链
  • _run_buy:走采购链
  • _run_manufacture:走制造链

所以你看到的“出库单”“采购单”“生产单”,不是销售模块自己硬编码出来的,而是规则引擎根据 route、warehouse、product 和 company 决定的。


最容易误解的三个点

1)确认销售单,不等于创建发货单

对某些产品,它可能只是在系统里留下一个需求痕迹,后面再由库存规则生成真正的执行对象。

2)订单头不是唯一入口

真正参与链路判断的,是订单行级别的数据。只改订单头,往往不够。

3)销售确认后的结果不是单一的

同一套代码,可能产出:

  • delivery picking
  • RFQ / PO
  • manufacturing order

这取决于路线,而不是“销售模块默认总是发货”。


实战里怎么改最稳

如果你要扩展这条链路,优先考虑这几个点:

  • 先改 procurement values,再让规则引擎接手
  • 需要自定义履约逻辑时,优先看 route / stock.rule
  • 调试时记得看 stock.reference,它会帮你把销售和下游动作串起来
  • 不要轻易在 sale.order._action_confirm() 里硬塞创建库存单据的代码

真正稳的做法,是让销售继续负责需求表达,让库存规则负责执行决策


一句话总结

Odoo 的销售确认不是“造单”,而是“发起需求”。

sale.order 把业务确认下来,sale.order.line 把需求包装成 procurement,stock.rule 再把需求分流成发货、采购或制造。

DISCUSSION

评论区

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