分包补料

Odoo 分包补料为什么经常跑错供应商位置:Resupply Route、Subcontractor Location 与收货联动讲透

很多团队以为分包补料只是从仓库发一张内部调拨,但 Odoo 源码里其实把仓库规则、供应商分包位置、收货单触发的分包 MO 全绑在一起。本文讲清这条补料链。

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

先说结论

Odoo 的分包补料不是“给供应商发一张内部调拨”这么简单。

它真正要解决的是三个问题:

  1. 组件该从哪个仓位送出去
  2. 送到哪个分包商位置才算库存语义正确
  3. 分包收货时,系统如何把外部加工结果和内部制造链重新接起来

所以源码里你会同时看到:

  • 仓库级 resupply route
  • property_stock_subcontractor
  • 公司级 subcontracting_location_id
  • 收货 move 自动识别 subcontract BOM
  • 收货后创建/驱动分包 MO

一句话概括:

分包补料的难点不是“发货”,而是“把库存位置、补料路线和外协制造语义对齐”。

为什么很多项目会觉得“补料跑错位置”

因为实施现场常把三个概念混成一个:

  • 供应商地址
  • 供应商普通库存位置
  • 供应商分包专属位置

但 Odoo 在 mrp_subcontracting 里不是这么想的。

res.partner 与相关模型上,源码给分包商准备了专门位置语义;在 picking 计算位置时,又会优先取:

  • partner 的 property_stock_subcontractor
  • 如果没配,再回落到 company 的 subcontracting_location_id

也就是说,Odoo 想表达的不是“货去供应商那边就行”,而是:

这批货进入的是‘我司视角下,寄存在这个分包商处的库存位置’。

这就是为什么位置一旦配错,后续所有补料、收货、追溯都会显得别扭。

仓库为什么还要多出一套分包补料路线

addons/mrp_subcontracting/models/stock_warehouse.py 里,仓库被扩展了几组关键字段:

  • subcontracting_to_resupply
  • subcontracting_route_id
  • subcontracting_type_id
  • subcontracting_resupply_type_id

这说明 Odoo 并没有把分包补料塞进普通内部调拨里糊弄过去,而是给它一套专门仓库规则。

更关键的是 _generate_global_route_rules_values()

一条规则:把本仓库存拉到分包商位置

有一条规则会把:

  • location_src_id = lot_stock_id
  • location_dest_id = subcontract_location_id

用于 Resupply Subcontractor 的补料动作。

另一条规则:在按单补料场景下,把分包商位置和生产语义连起来

还有一条全局 route 会把分包商位置与生产位置语义串起来,支撑按单触发的链路。

这说明 Odoo 不是只在做“库存移动”,而是在做:

  • 组件送去外协点
  • 外协点接住制造语义
  • 成品再从外协制造结果回到我方收货链

收货单为什么会反向触发分包制造单

mrp_subcontracting/models/stock_move.py 里,_action_confirm() 会扫描满足条件的 move:

  • 来源位置是 supplier
  • 目的位置不是 supplier
  • 存在可匹配的 subcontract BOM

一旦识别成立,系统会:

  • is_subcontract = True
  • 把 move 的 location_id 改成分包商位置
  • 然后调用 picking 的 _subcontracted_produce()

这个动作非常关键。

它表示:

Odoo 不是等你手工再建一张外协 MO,而是把这张收货 move 直接识别成“某个分包制造结果的入口”。

所以分包收货不是链路终点,而是制造回流的触发点。

picking 为什么还要二次修正 destination location

stock_picking.py_compute_location_id() 里,如果这是分包 resupply transfer,并且 partner 上配了 property_stock_subcontractor,系统会把 location_dest_id 指向那个供应商分包位置。

这说明 Odoo 对位置语义很执着:

  • 单据的作业类型是补料,还不够
  • partner 维度的分包位置还要覆盖进来

如果你在项目上看到“同样是补料,有的去公司默认分包位置,有的去供应商专属位置”,这往往不是随机现象,而是配置层级在生效。

为什么回写收货日期还会影响分包 MO

stock_move.py 里还做了一件很多人容易忽略的事:

  • 如果分包收货 move 的日期被改
  • 系统会把关联分包 MO 的 date_start / date_finished 同步写过去

这意味着对 Odoo 来说,分包收货日期不是普通收货字段,而是外协制造完成时点的重要代理值。

所以你在历史修单、回填日期时,实际上可能在改制造侧时间语义。

新手最容易误解的点

1)分包补料不是普通内部调拨

它背后绑定了专门 route、专门 operation type 和分包位置语义。

2)供应商地址不等于分包库存位置

property_stock_subcontractor 才是库存链路真正关心的位置。

3)分包收货不是单纯收成品

收货 move 会被识别、转义,并驱动分包制造链闭环。

4)日期、位置、partner 三者是联动的

你以为只是改收货时间或 partner,实际上可能在改分包制造链路的时间和库存归属。

实施和开发注意点

一,优先设计“位置语义”而不是只设计单据流程

很多项目图上把 PO、送货单、收货单画清楚了,但没有先想明白:

  • 分包商在系统里是哪个库存位置
  • 默认公司级位置够不够
  • 哪些供应商需要自己的专属分包位置

这一步不清,后面 route 再精致也会乱。

二,做二开时不要只盯采购单

分包逻辑真正的主链路大量落在:

  • stock rule
  • stock move
  • picking
  • subcontract MO

如果只在采购单按钮上加逻辑,很容易补不全。

三,排错时按这个顺序查

  1. partner 是否配置 property_stock_subcontractor
  2. company 默认 subcontracting_location_id 是否合理
  3. warehouse 的 subcontracting_to_resupply 和 resupply picking type 是否启用
  4. 收货 move 是否被识别成 is_subcontract
  5. _subcontracted_produce() 是否真的建出了对应分包 MO

最后总结

Odoo 的分包补料设计,比很多人以为的要“库存化”得多。

它不是把委外加工当成采购备注,而是明确建模为:

  • 组件送往分包位置
  • 分包位置承接外部制造语义
  • 收货单触发制造回流
  • 位置、路线、partner 配置共同决定链路是否成立

一句话记住:

分包补料的关键不是把料送出去,而是把料送到“正确的外协库存语义里”。

DISCUSSION

评论区

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