Odoo 19 库存出入库自动生成会计日记账 —— 配置指南
Odoo 19 库存出入库自动生成会计日记账 —— 配置指南
适用版本:Odoo 19 社区版(
stock_account模块,社区版自带)
适用场景:采购入库、销售出库、生产领料/入库、盘点盈亏等出入库操作后,系统自动在「库存日记账」过一条会计凭证。
文档性质:原生功能配置说明,无需开发。
0. 一句话原理
出入库单点「验证」→ stock.move 转 done → 系统判定是否满足自动过账条件 → 满足则在库存日记账生成并过账一条 account.move(会计凭证)。
整套机制由 stock_account 模块实现,前提是安装并应用 stock_account(依赖 stock + account)。
1. 前置条件
- 已安装 Inventory(stock) 与 Invoicing/Accounting(account) 模块。
- 已安装并应用
stock_account(库存估值与会计联动)。社区版自带,App 搜索 "Stock Accounting" 或在模块列表启用。 - 公司已设置好会计科目表(Chart of Accounts)与至少一个库存日记账。
- 操作用户属于「会计 / 库存」权限组,且拥有相关库位、产品类别的配置权限。
2. 必须同时满足的 5 个过账条件
下列 5 条全部满足时,一次出入库才会生成会计凭证(对应源码 stock.move._should_create_account_move):
| # | 条件 | 在哪配 |
|---|---|---|
| ① | 产品为 库存型商品(Storable),非服务/耗材 | 产品主数据 |
| ② | 该移动有价值(is_valued) |
自动判定 |
| ③ | 源库位或目的库位至少一个配了 valuation_account_id |
库位 |
| ④ | 移动数量 ≠ 0 | 单据 |
| ⑤ | 产品估值方式 = 永续/自动(Perpetual / real_time) | 产品类别 |
最容易漏的是 ③ 和 ⑤。任一不满足 → 静默不生成凭证,不会有报错。
3. 配置步骤(三层:公司 → 类别 → 库位)
Step 1 ── 公司层配置
路径:Accounting → Configuration → Settings(或 Inventory → Configuration → Settings)
| 配置项 | 说明 | 示例值 |
|---|---|---|
Stock Journal(库存日记账) account_stock_journal_id |
自动分录写入的日记账;生成分录时实际取的就是公司这个字段 | 日记账「库存估值 / Stock Journal」,类型选 General 或专用的 Inventory Valuation(若可用) |
Stock Valuation Account(库存估值科目) account_stock_valuation_id |
公司默认的库存资产科目,会作为产品类别的兜底 | 1403 库存商品(资产类) |
Inventory Valuation(库存估值方式) inventory_valuation |
新建产品类别的默认值;Perpetual=自动过账,Periodic=仅出报表 |
Perpetual |
Anglo-Saxon Accounting(盎格鲁-撒克逊) anglo_saxon_accounting |
是否启用"账单轧差暂估"模式(进阶,见第 7 节) | 初期可关闭,熟悉后再开 |
💡 保存公司配置时,系统会自动把上述库存日记账、库存估值科目、估值方式作为默认值下发到产品类别(无需逐个类别手填)。
Step 2 ── 产品类别配置
路径:Inventory → Configuration → Product Categories
对每个需要自动过账的类别设置:
| 配置项 | 取值建议 | 说明 |
|---|---|---|
| Costing Method(成本计价) | Standard / FIFO / Average (AVCO) |
决定出库成本如何计算 |
| Inventory Valuation(库存估值) | Perpetual ⚠️ |
必须选永续才会自动过账;选 Periodic 则只出报表 |
| Stock Valuation Account(库存估值科目) | 1403 库存商品 |
该类别库存的"家",资产科目 |
| Stock Journal(库存日记账) | 「库存估值」日记账 | 可覆盖公司默认值(可选) |
| Price Difference Account(价格差异科目) | 1404 材料成本差异 等 |
标准成本与实际采购价差额(可选) |
Step 3 ── 库位配置(Odoo 19 的关键变化)
路径:Inventory → Configuration → Locations
⚠️ Odoo 19 的核心架构变化:自动分录的对方科目由 库位上的
Stock Valuation Account(valuation_account_id) 决定,而不是旧版产品类别上的 input/output 科目。
配置原则:
- 内部库位(Internal)/ 在途(Transit):不要配
valuation_account_id(它们是库存资产本身的存放点)。 - 边界库位(与公司外部交互的库位):必须配
valuation_account_id,表示"货物进出公司库存时的对方/抵销科目"。
按业务需要配置以下边界库位(Odoo 默认已创建,补上科目即可):
| 库位(usage) | 典型名称 | valuation_account_id 建议科目 |
业务含义 |
|---|---|---|---|
supplier 供应商 |
Vendors | 1402 在途物资 / GRNI 暂估应付 |
采购入库时的贷方(暂估) |
customer 客户 |
Customers | 6001 主营业务成本 / COGS |
销售出库时的借方(成本) |
inventory 盘点 |
Inventory Loss | 1901 待处理财产损溢 |
盘点盈亏的对方科目 |
production 生产 |
Production | 4101 生产成本 / WIP |
生产入库/领料的对方科目 |
同一公司可有多个内部库位(多仓库/多仓位),它们之间调拨不过账(符合预期)。
若要让某一内部库位对接特殊科目(如委外、独立核算部门),才在该内部库位上单独配valuation_account_id。
Step 4 ── 产品主数据
路径:Inventory → Products → Products
- Product Type =
Storable(库存型商品) ⚠️(不能是 Consumable / Service) - Product Category = 已按 Step 2 配好的类别
- Cost(标准成本):Standard 计价时作为入库估值依据
4. 业务场景 × 科目流向对照表
设:P = 产品类别库存估值科目(如 1403 库存商品);V(loc) = 该库位的 valuation_account_id。
分录借贷由源码 _get_account_move_line_vals 决定:
if 源库位.valuation_account_id: # 货物从边界进入库存
借 = P(库存资产) ; 贷 = V(源库位)
else: # 货物从库存流向边界
借 = V(目的库位) ; 贷 = P(库存资产)
| 业务 | 库位流向 | 借方 | 贷方 | 金额 |
|---|---|---|---|---|
| 采购入库 | supplier → internal | 库存资产 P | 暂估应付 V(supplier) | 入库数量×单位成本 |
| 销售出库 | internal → customer | 主营成本 V(customer) | 库存资产 P | 出库数量×单位成本 |
| 生产完工入库 | production → internal | 库存资产 P | 生产成本 V(production) | 完工成本 |
| 车间领料 | internal → production | 生产成本 V(production) | 库存资产 P | 领料成本 |
| 盘亏 | internal → inventory(loss) | 待处理损溢 V(inventory) | 库存资产 P | 盘亏金额 |
| 盘盈 | inventory(loss) → internal | 库存资产 P | 待处理损溢 V(inventory) | 盘盈金额 |
| 内部调拨(同公司) | internal → internal | — 不生成凭证 — | — | — |
| 客户退货 | customer → internal | 库存资产 P | 主营成本 V(customer) | 红字/反向 |
| 采购退货 | internal → supplier | 暂估应付 V(supplier) | 库存资产 P | 红字/反向 |
5. 验证方法
5.1 操作验证
- 做一张采购入库单 → 点「Validate(验证)」。
- 单据验证后,顶部出现 「Accounting / 会计」 智能按钮(显示分录数)。
- 点击进入,应看到一条
account.move:- 日记账 = 公司「库存日记账」
- 状态 =
Posted(已过账) - 两行:借库存资产、贷暂估应付;金额 = 入库数量 × 单位成本。
5.2 反查
- 会计 → 配置 → 日记账 → 进入「库存日记账」,查看所有自动生成的凭证。
- 任意出入库单的
stock.move,其account_move_id字段直接指向生成的会计凭证。 - 库存 → 报告 → 库存估值(Inventory Valuation):查看每次出入库形成的估值历史。
5.3 没生成凭证时的排查清单
按顺序检查:
- ☐ 产品类型是 Storable?(Consumable 不会触发)
- ☐ 产品类别 Inventory Valuation = Perpetual?
- ☐ 涉及的边界库位配了 valuation_account_id?(最常见的坑)
- ☐ 该次移动数量非零、产品有成本价?
- ☐ 公司配了 库存日记账
account_stock_journal_id?(否则_create_account_move无法写 journal) - ☐ 若是内部调拨 → 设计上就不过账,属正常。
6. 成本计价方法(Costing Method)对金额的影响
自动凭证的金额由成本计价方法决定,在 stock.move._set_value() 中计算:
| 方法 | 入库取值 | 出库取值 | 适用 |
|---|---|---|---|
| Standard(标准成本) | 产品 standard_price |
产品 standard_price |
成本稳定、管控简单 |
| FIFO | 实际采购价 | 按先进先出消耗库存层 | 精细追踪真实成本 |
| Average / AVCO(移动加权平均) | 实际采购价,并重算均价 | 当前加权平均价 | 折中,常用 |
改变类别的 Costing Method 会触发存量产品价格重算(
product.category.write → _update_standard_price),生产环境慎改。
7. 进阶:Anglo-Saxon(盎格鲁-撒克逊)模式
何时开启:希望"入库时走暂估,收到采购账单时再轧差到实际应付",即采购成本按账单确认、入库只暂估。
开启后(公司 anglo_saxon_accounting = True),采购流程的科目流转:
采购入库: 借 库存资产 贷 暂估应付(GRNI)
收到账单: 借 暂估应付(GRNI) 贷 应付账款
借/贷 价格差异(若有)
需要额外配置:
- 供应商库位
valuation_account_id指向 GRNI/暂估科目(资产类,如1403 在途物资)。 - 产品类别的 Price Difference Account 处理标准价与实际价差。
- 账单与采购单的"三向匹配"会自动调整。
初次实施建议先关闭 Anglo-Saxon、跑通基础自动过账,再按需开启。
8. 附录:典型中国会计科目映射(示例,按贵司科目表调整)
| 角色 | 建议科目编码 | 科目名称 | 类型 |
|---|---|---|---|
| 库存资产 P | 1403 | 库存商品 | 资产 |
| 采购暂估/在途 | 1402 | 在途物资 / 1403暂估 | 资产 |
| 销售成本 | 6001(或 5401) | 主营业务成本 | 损益 |
| 生产成本/WIP | 4101 | 生产成本 / 1411 在产品 | 资产/成本 |
| 盘点损溢 | 1901 | 待处理财产损溢 | 资产 |
| 价格差异 | 1404 | 材料成本差异 | 资产 |
9. 关键源码索引(便于二次确认/排错)
| 关注点 | 文件 | 方法 |
|---|---|---|
| 触发时机 | stock_account/models/stock_move.py |
_action_done → _create_account_move |
| 过账判定 | 同上 | _should_create_account_move |
| 借贷科目 | 同上 | _get_account_move_line_vals |
| 入/出库判定 | 同上 | _is_in / _is_out / _get_in_move_lines / _get_out_move_lines |
| 库位是否估值 | stock_account/models/stock_location.py |
_should_be_valued(usage in (internal, transit) 且有公司) |
| 产品类别字段 | stock_account/models/product.py |
property_valuation / property_cost_method / property_stock_valuation_account_id |
| 公司字段 | stock_account/models/res_company.py |
account_stock_journal_id / account_stock_valuation_id |
| 默认值下发 | 同上 | write(374–377 行) |
10. 附录:FIFO 与 AVCO 成本变化实测对比
实测环境:
odoo19c.test(l10n_cn 中国科目表,CNY,Anglo-Saxon 开启)。
测试产品:T-AVCO(半成品类,Average 计价)、T-FIFO(成品类,FIFO 计价)。
场景:各做 2 次不同单价采购 + 1 次部分出库,追踪每次操作后的库存数量、单位成本与库存总价值。
以下单价均为不含税净价(采购单行已清税,见 10.5)。
10.1 AVCO(移动加权平均)成本轨迹
| 步骤 | 操作 | 库存 | 单位成本 | 库存总价值 | 本次金额 | 生成分录 |
|---|---|---|---|---|---|---|
| 初始 | — | 0 | — | 0 | — | — |
| 1 | 采购入库 100件@¥100 | 100 | ¥100.00 | ¥10,000 | +¥10,000 | 借1405库存 / 贷1402.01暂估 |
| 2 | 采购入库 100件@¥200 | 200 | ¥150.00 ←重算 | ¥30,000 | +¥20,000 | 借1405库存 / 贷1402.01暂估 |
| 3 | 销售出库 50件 | 150 | ¥150.00 | ¥22,500 | −¥7,500 | 借5401主营业务成本 / 贷1405库存 |
- 均价重算公式:
(100×100 + 100×200) / 200 = ¥150 - 出库取值:按当前均价 ¥150 × 50 = ¥7,500
- 出库后均价不变(出库只消耗库存,不改变单位成本)
10.2 FIFO(先进先出)成本轨迹
| 步骤 | 操作 | 库存 | 单位成本 | 库存总价值 | 本次金额 | 生成分录 |
|---|---|---|---|---|---|---|
| 初始 | — | 0 | — | 0 | — | — |
| 1 | 采购入库 100件@¥100 | 100 | ¥100.00 | ¥10,000 | +¥10,000 | 借1405库存 / 贷1402.01暂估 |
| 2 | 采购入库 100件@¥200 | 200 | ¥150.00 | ¥30,000 | +¥20,000 | 借1405库存 / 贷1402.01暂估 |
| 3 | 销售出库 120件 | 80 | ¥200.00 ←更新 | ¥16,000 | −¥14,000 | 借5401主营业务成本 / 贷1405库存 |
- 出库120件分层消耗:
- 先耗第一批 100件 × ¥100 = ¥10,000
- 再耗第二批 20件 × ¥200 = ¥4,000
- 合计出库成本 = ¥14,000
- 剩余库存:80件全部来自第二批@¥200 = ¥16,000,单位成本随之更新为 ¥200
10.3 核心差异对比
| 维度 | AVCO 平均成本 | FIFO 先进先出 |
|---|---|---|
| 出库成本计算 | 当前移动平均价 × 数量 | 按入库批次顺序逐层消耗,跨批次时成本分层累加 |
| 出库对单位成本的影响 | 无影响(均价不变) | 有影响(出库后单位成本 = 剩余批次单价) |
| 物价上涨时(本例) | 出库成本被平滑 | 出库成本偏低(耗旧批次)、期末库存价值偏高(新批次) |
| 跨批次出库金额 | 均价 × 数量(单一单价) | Σ(各批次数量 × 各批次单价) |
| 期末库存价值 | 均价 × 库存量 | Σ(剩余各批次价值) |
同样"出库50件":AVCO 按 ¥150 = ¥7,500;若 FIFO 出50件则全部来自第一批 = 50×¥100 = ¥5,000。差异体现了两种方法对利润(成本)与资产(库存价值)的不同刻画。
10.4 出入库分录(两种方法一致)
Anglo-Saxon 模式下,无论 AVCO 还是 FIFO,科目流向相同,仅金额不同(金额由 10.1/10.2 的计价方法决定):
| 业务 | 借方 | 贷方 | 金额来源 |
|---|---|---|---|
| 采购入库 | 1405 库存商品 | 1402.01 暂估应付(GRNI) | 入库数量 × 实际采购净价 |
| 销售出库 | 5401 主营业务成本 | 1405 库存商品 | 出库数量 × 计价方法算出的成本 |
10.5 Odoo 19 Community 实操要点(实测踩坑记录)
- 成本记录无独立层级表:社区版移除了
stock.valuation.layer模型(仅企业版相关功能引用其名)。每次出入库的成本变化体现在product.total_value(库存总价值)、product.standard_price(单位成本)、以及自动生成的account.move分录金额上。要回溯历史成本变化,查库存日记账(journal = STJ)的分录即可。 - 入库成本必须经采购单传递:直接创建拣货/移动并设
price_unit不生效——成本会兜底用产品standard_price(见_get_value_data优先级:发票账单 → 生产 → SO/PO 报价单行 → 退货 → standard_price 兜底)。必须走 采购订单(PO)流程,价格才通过purchase_stock._get_value_from_quotation()(内部调purchase_line_id._get_stock_move_price_unit())正确传递。 - l10n_cn 默认带 13% 进项税:采购单行会自动套用
l10n_cn_purchase_excluded_13,导致价格被税剥离(如 ¥100 → ¥88.5)。若要按净价做成本演示/测试,在采购单行清空税(tax_ids = [(6,0,[])]);生产环境则按含税/不含税实际业务设置。 - 出库验证触发 SMS 通知向导:脚本/接口中调
picking.button_validate()会被confirm.stock.sms向导拦截,单据卡在assigned、库存不减少。绕过办法:先button_validate()(忽略返回的向导 dict),再调用move._action_done()真正完成移动。界面操作正常点击向导按钮即可。 - 移动完成数量需显式设置:
stock.move没有reserved_quantity字段(19 已改名),出库前需显式设move.quantity = 实发数量,否则button_validate报 "Validating a zero quantity transfer"。
关联字段名变化(19):
purchase.order.line.taxes_id→tax_ids;purchase.order.line.product_uom→product_uom_id;sale.order.line.product_uom→product_uom_id;stock.move无name字段(自动生成);新建库存型产品用type='consu'+is_storable=True(无detailed_type、type中无'product')。
文档结束。配置中如遇"未生成凭证",请优先回到第 2 节的 5 条件与第 5.3 节排查清单逐项核对。

浙公网安备 33010602011771号