库存到总账

库存价值为什么最后会变成会计分录:stock_account 的 _action_done 链路

从 stock_account._action_done 到 _create_account_move,讲清楚实时报价库存怎样在过账时写入总账。

会计 库存
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

先说结论

在 Odoo 里,库存价值不是“等月底再统一算”。

对实时报价(real_time)产品来说,库存 move 在完成时就会往总账写分录

所以你会看到一个很典型的链路:

  • 库存 move 完成
  • 价值被计算出来
  • 会计分录生成
  • journal entry 过账

这条链把库存和会计直接接在了一起。


入口:stock_account.StockMove._action_done()

addons/stock_account/models/stock_move.py 里,真正关键的逻辑顺序非常讲究:

moves_out = self.filtered(lambda m: m._is_out())
moves_out._set_value()
moves = super()._action_done(cancel_backorder=cancel_backorder)
moves_in = moves.filtered(lambda m: m.is_in or m.is_dropship)
moves_in._set_value()
moves._create_account_move()
moves_out.product_id.filtered(lambda p: p.cost_method == 'fifo')._update_standard_price()

这里最值得注意的是:

  • 出库 move 先算值,因为 FIFO 需要当前栈
  • 入库 move 在真正 done 之后再算值,因为实际成本此时更明确
  • 最后统一创建会计分录

这不是随便写的顺序,而是为了保证 valuation 计算尽量贴近真实业务。


什么样的 move 才会生成分录

不是每一笔库存移动都会打总账。

_should_create_account_move() 只允许满足这些条件的 move 进入会计链:

  • 产品是可库存的(storable)
  • 这笔 move 是 valued 的
  • 来源或目的地点有 valuation account
  • 产品的 valuation 方式是 real_time

也就是说,会计分录不是 move 的默认副作用,而是 valuation 策略的结果。

这点很重要。

如果你的产品是 manual valuation,或者 location 没有对应 valuation account,链路就会被挡住。


_create_account_move() 如何拼出双向分录

创建会计分录时,Odoo 不是只写一边,而是写一对平衡分录。

核心逻辑在 _get_account_move_line_vals()

if self.location_id.valuation_account_id:
    debit_acc = self.product_id._get_product_accounts()['stock_valuation']
    credit_acc = self.location_id.valuation_account_id
else:
    debit_acc = self.location_dest_id.valuation_account_id
    credit_acc = self.product_id._get_product_accounts()['stock_valuation']

这段代码告诉你两件事:

  1. 库存价值账户永远是核心
  2. 另一边要看 source location 还是 destination location 有没有 valuation account

然后它会用 self.value 作为金额,生成一借一贷两条行。

这也是为什么库存会计不是“简单把数量乘单价记一下”,而是要把库位、产品和成本法一起考虑进去


为什么这条链和 FIFO、标准价都有关

stock_account 还会在出库后更新 FIFO 产品的 standard price。

这意味着:

  • 成本法不同,计算路线不同
  • FIFO 更依赖当前堆栈与出库顺序
  • real_time 让会计分录在业务发生时同步写入

如果你只盯着财务分录,容易忽略库存侧的价值来源; 如果你只盯着库存数量,又会漏掉总账已经过账这件事。

所以库存价值链的完整视角应该是:

数量在库存,价值在 move,总账分录在 account.move。


最容易踩坑的地方

1)把价值问题当成数量问题

数量对了,不代表 valuation 对了。先看产品成本法,再看 location valuation account。

2)只查 stock,不查 account

如果分录没出来,重点查 _should_create_account_move() 的条件有没有被拦住。

3)忽略退货和 dropship 分支

_is_out()_is_in()_is_dropship() 这些分支会影响值的计算时点。


实战建议

排查库存金额不对时,最有效的顺序通常是:

  1. 确认产品是 real_time valuation
  2. 确认 location 上有 valuation account
  3. _action_done() 的前后顺序
  4. 检查 move value 有没有在 FIFO/standard price 场景下被更新
  5. 再看 journal entry 的借贷方向

这样查,通常比“直接去改会计凭证”更快。


一句话总结

Odoo 的库存会计不是月底补账,而是 move 完成时就把价值写进总账。

stock_account._action_done() 负责价值时点,_create_account_move() 负责分录生成,成本法和 valuation account 则决定这条链能不能走通。

DISCUSSION

评论区

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