先说结论
很多人理解 Odoo 的“项目 + 制造”联动时,会以为它只是:
- BOM 上能填项目
- 制造单上能看到项目
- 项目页多两个按钮看 BOM 和 MO
但如果你读 /home/ubuntu/odoo-temp/addons/project_mrp/ 和 project_mrp_account/,会发现官方做的是更完整的一条分析成本链:
- BOM 可以挂项目
- MO 会默认吃 BOM 上的项目
- 从项目页创建 MO 时又会反向把项目上下文传进去
- 原料 move 会继承项目分析分摊并生成制造类分析行
- 工单工时也能按照项目分析分摊写入 analytic entries
所以项目制造联动的真正重点不是“项目能打开制造单”,而是:
制造活动如何被正式纳入项目成本与分析维度。
第一层:BOM 与 MO 上的项目字段为什么都要存在
在 project_mrp 里:
mrp.bom新增project_idmrp.production新增project_idmrp.production._compute_project_id()会在通常场景下从 BOM 带入项目
这说明官方不想把项目字段只放在一个位置。
因为制造链条里有两个不同阶段:
1. 设计/准备阶段
BOM 表示“这套物料/工艺结构属于哪个项目背景”。
2. 执行阶段
MO 表示“这次实际生产执行归属于哪个项目”。
如果只有 BOM 有项目,执行单据层不够好用;如果只有 MO 有项目,很多默认继承和统计入口又不好做。
所以两边同时挂项目,是为了让模板侧与执行侧都能保留项目语义。
第二层:为什么从项目页发起和从 BOM 发起都能成立
mrp.production._compute_project_id() 在非 from_project_action 场景下,会默认让 MO 继承 BOM 的项目。
而从项目页进入制造动作时,context 又会带:
default_project_idfrom_project_action
这背后的设计很细:
- 如果你是从 BOM/制造流过来,项目应该从 BOM 继承
- 如果你是从项目视角主动发起,项目应该以当前项目为准
也就是说,官方并没有硬写一种唯一来源,而是根据入口不同决定优先权。
这正是成熟业务系统的做法:
同一个字段的默认值,取决于操作上下文,而不是单纯依赖某一个上游单据。
第三层:原料 move 为什么也要吃项目分析分摊
在 project_mrp_account/models/stock_move.py 里,raw_material_production_id.project_id 会参与:
_get_analytic_distribution()_prepare_analytic_line_values()_prepare_analytic_lines()
意思是只要库存移动属于某张制造单,而那张制造单又归属于项目,那么原料消耗就能按项目分析分摊进入分析账。
而且源码同样会校验制造业务域下必填的分析计划是否齐全,不齐全就拦截。
这说明项目制造成本并不是“MO 页面上有个项目字段”那么浅,而是会一直下沉到:
- 原料领用
- 分析分摊
- 成本分析行
这才是项目制造成本真正可算的基础。
第四层:工单工时为什么也会写到项目分析里
project_mrp_account/models/mrp_workorder.py 扩展了:
_create_or_update_analytic_entry_for_record()
在标准工单工时分析行之外,它还会基于项目的 _get_analytic_distribution() 再生成 / 更新 mo_analytic_account_line_ids。
这一步很关键,因为制造项目的成本不只是原料,还包括:
- 人工工时
- 机台 / 工序执行时间所代表的成本
所以如果你只把库存消耗进项目,不把工单工时也进项目,那项目制造成本仍然是不完整的。
官方这里等于是在说:
制造项目的分析成本,必须同时覆盖材料消耗和执行工时。
第五层:项目页上 BOM / MO 按钮的真正意义
在 project_mrp/models/project_project.py 里,项目会显示:
- BOM 数量
- Manufacturing Orders 数量
- 打开相关列表/表单的动作
很多人会把这些按钮当成“方便跳转”。
但真正的含义其实是:
- BOM 与 MO 已被承认为项目上下文中的一等对象
- 项目不是只跟任务和工时相关
- 对某些交付型制造业务,项目可以成为计划、执行、成本回看的统一入口
这意味着项目在 Odoo 里正在从任务容器演化成跨模块交付容器。
新手最容易误解的 4 件事
1. 以为制造项目联动就是 MO 上多一个项目字段
不对,真正关键是分析成本链路也跟着打通。
2. 以为 BOM 上有项目就够了
不对,MO、raw material move、workorder 都会继续吃这个项目语义。
3. 以为项目制造成本只包含原料领用
不对,工单工时也会写入项目分析行。
4. 以为从不同入口创建 MO,项目默认逻辑都一样
不对,源码会根据 context 区分优先来源。
实战里最该注意什么
1. 客户说“制造成本没进项目”,不要只查 MO 表头
至少要继续查:
- raw material move 的 analytic distribution
- manufacturing_order 域下的 mandatory plans
- workorder analytic entries 是否生成
2. 多项目、多 BOM 共享环境里,要特别留意项目默认值来源
从 BOM 发起和从项目发起,默认逻辑可能不同。
3. 如果项目利润只看到了材料、没看到人工,不一定是报表问题
也可能是工单工时分析行根本没按项目分摊出去。
一句话记忆法
Odoo 制造项目联动不是给 BOM / MO 多一个项目字段,而是把 BOM、制造单、原料消耗和工单工时一起拉进项目分析成本体系。
DISCUSSION
评论区