先说结论
在 Odoo 里,落地成本不是记一笔额外费用这么简单。
它真正要解决的是:
把运输费、关税、杂费这些额外成本,合理地分摊进已经入库的货物价值里。
所以它关心的不只是会计分录,还关心:
- 这些费用该摊到哪些 stock move
- 每条 move 分到多少
- 最终怎样影响库存估值
- 哪些产品根本不该参与这类分摊
为什么落地成本不是普通费用单
因为普通费用只解决这笔钱花了。
落地成本要解决的是:
- 这笔钱为哪些货服务
- 应该归入哪些货值
- 之后出库成本和库存价值要不要跟着变化
也就是说,它是费用问题,但落点在库存价值。
官方模型里最关键的几个角色
从 stock_landed_costs 模块看,核心对象包括:
stock.landed.coststock.landed.cost.linesstock.valuation.adjustment.lines
你可以把它们理解成:
- 主单:本次要做一轮落地成本调整
- 成本行:有哪些额外费用项目
- 调整行:这些费用最终被分到哪些库存 move 上
为什么不是所有库存移动都能参与
源码里 get_valuation_lines() 有非常明确的过滤条件。
它只处理:
- 没取消的 move
- 有数量的 move
- 产品成本方法是
fifo或average
这说明 Odoo 很清楚:不是所有产品估值策略都适合这样补成本。
compute_landed_cost() 真正在做什么
这是整条链路里最值得理解的函数之一。
它会:
- 先拿到所有目标 move 的估值基础数据
- 针对每条成本行,为每个目标 move 生成 adjustment line
- 按所选分摊方法算每条 adjustment 应分到多少
- 处理 rounding difference,把尾差补齐
也就是说,落地成本的核心不是记账,而是分摊计算。
为什么分摊方法这么重要
官方提供了这些 split method:
- Equal
- By Quantity
- By Current Cost
- By Weight
- By Volume
这其实是在回答一个业务问题:
这笔额外成本,按什么逻辑才算分得合理?
比如运费可能适合按重量或体积,高货值商品可能更适合按当前成本比例分摊。
button_validate() 为什么不只是确认
很多人以为 validate 只是把状态从 draft 改成 done。
但源码里它会先检查:
- 有没有 adjustment lines
- 分摊总额和成本总额是否对得上
- 哪些产品需要真实会计处理
然后再去创建 journal entry,并把该入账的价值调整真正落下去。
所以 validate 的真实含义是:
确认这次落地成本分摊结果可以正式进入库存价值和会计世界。
一句话记忆法
它不是补一笔费用,而是把额外采购相关成本重新分配进库存价值的一条估值链。
DISCUSSION
评论区