采购价差

Odoo 采购价差不是“价格填错了”而已:Vendor Bill、标准成本与 Price Difference Account 怎么串起来

收货价和账单价不一样时,Odoo 不是只改一个单价字段。本文把标准成本、价差科目、Anglo-Saxon 分录和库存价值边界讲清楚。

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

先说结论

很多人看到 Vendor Bill 价格和采购单、收货成本不一致时,第一反应是:

  • 是不是采购价填错了?
  • 为什么账单一过账,库存或费用就怪怪的?

但 Odoo 的真实逻辑更像:

采购价差不是一个前端显示问题,而是“收货估值口径”和“账单确认口径”之间的差额,要不要以及怎么记到账里。

特别是在 标准成本 + 实时库存估值 + Anglo-Saxon 场景下,这件事非常关键。


先分清三种价格,不然很容易脑内混线

一条采购业务里,至少可能同时存在:

  1. PO/收货价格:库存 move 在收货时采用的价值口径
  2. 产品标准成本:某些会计逻辑里拿来作为估值参考
  3. Vendor Bill 价格:供应商此刻正式要求你确认的单价

如果这三者完全一致,世界很安静。

但现实里经常会出现:

  • 采购单先按一个价格下单
  • 货先按一个估值口径收进来
  • 最终 Vendor Bill 又改了价格,或者带折扣、汇率差、补差

于是系统必须回答:

  • 差额打到库存?
  • 打到费用?
  • 打到价差科目?
  • 还是部分打库存、部分打 COGS?

源码里“价差”是被明确建模的

stock_account/models/product.py 里,你能看到 property_price_difference_account_id

帮助文本写得很直白:

  • 在 perpetual valuation 下,这个科目用来承接 标准价与账单价之间的差额

也就是说,Odoo 从模型层就承认:

采购价差不是异常噪音,而是一个应该被单独落账的业务对象。


Vendor Bill 过账时,系统在看什么

关键逻辑在 purchase_stock/models/account_invoice.py_stock_account_prepare_anglo_saxon_in_lines_vals()

这段代码说明了几个重点:

  • 只在 in_invoice / in_refund / in_receipt 且公司启用 Anglo-Saxon 时进入
  • 只处理满足库存会计条件的行
  • 对标准成本产品,会去找 property_price_difference_account_id
  • 然后计算 price_unit_val_dif 与相关数量 relevant_qty
  • 再额外生成两条分录:
  • 一条打到价差科目
  • 一条反向修正当前行科目金额

这就说明:

Vendor Bill 过账不是简单确认应付,而是在必要时补做“采购价差分录”。


_get_price_unit_val_dif_and_relevant_qty() 真正在比什么

purchase_stock/models/account_move_line.py 里,Odoo 会先算一个 valuation_price_unit

  • 基于产品标准价
  • 转成账单行单位
  • 再按账单日期换算到对应币种

然后再拿它和账单的 price_unit 去比较,得到:

  • price_unit_val_dif

换句话说,系统不是在比“PO 行显示价格”和“Bill 行显示价格”这么简单,而是在比:

当前账单的真实单价,与会计估值口径下应该参考的单价之间,差了多少。

这也是为什么汇率、单位、折扣一进来,很多人的直觉就会开始失效。


为什么部分已出库时,价差不会只落在库存里

Odoo 测试 test_price_diff_with_partial_bills_and_delivered_qties 很能说明问题。

它验证的是:

  • 部分数量已经卖出 / 发出
  • 部分数量还在库里
  • 这时再来一张价格不同的 Vendor Bill

系统处理思路不是“一刀切”。

而是:

  • 已经流出库存的那部分,不应再全留在库存价值里
  • 还在库里的部分,才适合继续反映到库存价值 / SVL
  • 因此会出现一部分直接走 COGS,一部分通过库存估值层调整

这很关键,因为它说明:

采购价差不是只看账单,也不是只看库存,而是要看“差额对应的货现在还在不在库里”。


实战里最容易误判的 4 件事

1. 把价差问题理解成采购单改单价失败

它往往已经进入库存估值与会计分录层了。

2. 只看 PO price_unit,不看账单币种和日期汇率

源码比较时会做币种换算。

3. 忽略标准成本 / FIFO / AVCO 的差异

不同成本法下,价差落账路径并不完全一样。

4. 以为所有价差都应继续留在库存里

部分数量已经出库时,差额语义会变。


一句话记忆法

Odoo 的采购价差,本质上是在协调“账单确认的真实采购成本”和“库存/会计当前采用的估值口径”之间的差额;货还在库里和已经流出库里,处理也会不一样。

DISCUSSION

评论区

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