先说结论
在 Odoo 里,制造相关的落地成本并不是只能挂采购收货。
mrp_landed_costs 明确支持把 stock.landed.cost 的目标模型设成 manufacturing,然后让系统去拿这批制造单的成品 stock moves做分摊基础。
所以关键理解不是“我能不能把运费记到 MO 上”,而是:
Odoo 是通过成品库存移动承接落地成本,而不是往制造单表头拍一笔总数。
为什么这点很重要
很多企业想把这些成本并入制造:
- 外协运输
- 入厂装卸
- 特殊包装
- 关税 / 附加杂费
但如果只是手工在 MO 上记个附加金额,库存估值、成品成本、后续毛利分析就不一定能跟着走。Odoo 这里选择的是更稳的路径:仍然通过 stock move / valuation 层入账。
源码里的关键设计
在 stock.landed.cost 的扩展里,Odoo新增了:
target_model = manufacturingmrp_production_ids
更关键的是 _get_targeted_move_ids():
- 先继承原有目标 move
- 再加上这些制造单的
move_finished_ids - 但减去
cost_share = 0的副产品 move
这里已经把边界讲得很清楚。
为什么是 finished moves,而不是 raw moves
因为 landed cost 的目标,是把额外成本并到被产出的价值承载体上,而不是并到已消耗掉的原料上。
原料在制造中通常已经通过领料或消耗进入成本结构;落地成本如果再去追原料端,很容易和原始采购估值混成一团。把它挂到 finished moves,逻辑更稳定:
- 谁是这次制造最终产出
- 谁应该吸收这笔额外成本
- 后续库存估值和销售成本怎么延续
为什么零 cost_share 的副产品会被排除
源码里这句非常有业务味道:
move_byproduct_ids.filtered(lambda move: not move.cost_share)被排除
这说明 Odoo 的立场是:
- 如果副产品明确承担成本份额,它可以进分摊池
- 如果副产品没有成本份额,就不要拿它去摊 landed cost
否则你会出现一种很怪的情况:副产品业务上没承担成本,但估值上却被分配到附加费用。
最常见的误区
1. 以为 landed cost 进制造就是改 MO 金额字段
不是。真正被作用的是 move / valuation。
2. 以为所有副产品都应分摊
是否参与,取决于它有没有真实成本份额语义。
3. 以为 raw material 更该承担落地成本
对制造目标的 landed cost 来说,系统更关心最终产出价值载体。
4. 以为它和采购 landed cost 逻辑完全一样
思路相通,但目标对象和 move 集合不同。
排错顺序
如果你发现制造落地成本没按预期分到某个产出,按这个顺序查:
- landed cost 的
target_model是否真是manufacturing - 是否选中了正确的
mrp_production_ids - 相关成品 move 是否存在且可用于估值
- 副产品是不是
cost_share = 0被系统自动排除 - 最后再检查成本行的 split method 和会计配置
一句话记忆法
Odoo 把制造落地成本记到 MO,并不是直接写 MO,而是先找到这张 MO 的成品 move,再沿着库存估值链去承接。
DISCUSSION
评论区