很多人第一次认真看 Odoo 银行日记账 Dashboard,都会产生一种强烈困惑:
- 这个 balance 为什么和总账不完全一样?
to check到底在数什么?- 为什么没有流水时还会出现图?
- direct payments 算不算真实银行余额?
- outstanding 和 misc operations 为什么也出现在同一张卡片上?
如果只从 UI 看,这些数字确实很像“一个银行账户余额看板”。
但 /home/ubuntu/odoo-temp/addons/account/models/account_journal_dashboard.py 的实现其实说明,Odoo 做的不是简单余额卡,而是一个给会计日常操作服务的运营看板。
关键方法包括:
account.journal._get_journal_dashboard_data_batched()account.journal._fill_bank_cash_dashboard_data()account.journal._get_bank_cash_graph_data()account.journal._get_journal_dashboard_bank_running_balance()account.journal._compute_current_statement_balance()account.journal._compute_last_bank_statement()
把这些连起来看,最重要的结论先说:
银行 Dashboard 展示的不是单一“银行余额”,而是把对账进度、银行流水态、直连付款、未结 outstanding 和人工待处理事项压缩到同一块操作面板里。
所以它本来就不该和总账余额一模一样。
一、入口方法已经暴露了设计目标:batched dashboard data
_get_journal_dashboard_data_batched() 会先给每个 journal 准备一份基础字典,然后依次调用:
_fill_bank_cash_dashboard_data()_fill_sale_purchase_dashboard_data()_fill_general_dashboard_data()_fill_onboarding_data()
这件事很重要,因为它说明 dashboard 的设计不是“每个 journal 各写各的字段”,而是:
先建立一个统一 dashboard 容器,再按 journal 类型往里填充不同视角的数据。
银行 journal 只是其中一种。
所以当你看到银行卡片里既有余额、又有待检查、又有拖拽导入提示时,不要惊讶——它本来就是混合型操作卡片。
二、to check 不是未对账余额,而是“需要人工复核的流水”
_fill_bank_cash_dashboard_data() 里有一段对 to_check 的聚合:
- 来自
account.bank.statement.line - 要求
move_id.checked = False - 且
move_id.state = 'posted'
这说明 to check 的核心语义不是:
- 银行没对上;
- 金额没平;
- 还没核销。
而是:
这条流水对应的 move 仍被标记为需要人工检查。
所以 to check 本质上是一个工作队列指标,不是余额指标。
很多项目把它误当“还有多少没对账”,就会越看越迷惑。
三、number_to_reconcile 也不是所有未核销流水,而是 checked 且未 reconciled 的 statement lines
源码里另一个查询统计的是:
st_line.is_reconciled IS NOT TRUEst_line_move.checked IS TRUEst_line_move.state = 'posted'
这和 to check 恰好形成分层:
to check:还没被人工确认通过number_to_reconcile:已经 checked,但还没真正完成 reconciliation
这非常像一个运营漏斗。
也就是说,Dashboard 不是只想告诉你“余额多少”,而是想告诉你:
- 还有多少流水在人工复核阶段;
- 还有多少已经确认、但未完成对账闭环。
从产品角度看,这是一张流程状态卡片,不是一张单口径资金报表。
四、为什么 account balance 还要加 direct payments
dashboard_data[journal.id]['account_balance'] 的来源特别值得注意:
journal.current_statement_balance + direct_payments_balance
也就是说,Dashboard 上看到的 account balance,并不只是 statement running balance。
它还会把某些 direct bank payments 叠加进去。
这表达的是一个很现实的产品判断:
用户在银行看板上关心的,不只是已进入 statement 的银行余额,还关心那些已经通过银行付款链进入系统、但尚未体现在 statement 路径里的直接付款影响。
所以这个 balance 更像“面向操作的资金视图”,而不是严格法定意义下的 statement ending balance。
这也正是为什么它不一定和你在总账或银行对账单上看到的某个单一数字完全一致。
五、outstanding 和 misc operations 会同卡展示,是因为看板关心“还有哪些钱没走完整路径”
_fill_bank_cash_dashboard_data() 还会准备:
outstanding_pay_account_balancenb_lines_outstanding_pay_account_balancemisc_operations_balancenb_misc_operations
这几项的共同特点是:
- 它们和 journal 资金路径有关;
- 但不一定都已经变成标准 statement line 的已完成银行对账状态。
尤其 misc operations 统计的是:
- 默认账户上的 move lines
- 没有关联
statement_line_id - 已过账
- 也不是 payment 生成的行
这就说明 Odoo 把 Dashboard 当成一个“还有哪些资金动作悬着”的视图。
不是所有钱都已经走完整银行 statement → reconcile 路径,有些还在:
- outstanding
- direct payment
- misc operation
这些都会影响会计人员的下一步动作,所以被并排展示。
六、为什么图表会出现 sample data
_get_bank_cash_graph_data() 的逻辑特别有意思。
如果:
- 最近没有真实 journal_result
- 且
not journal.has_statement_lines
系统会生成一段 sample graph data,并把 key 改成 Sample data。
这其实是个很典型的产品体验取舍。
Odoo 不希望一个新建银行 journal 的卡片显得完全空白,于是:
- 用随机但范围可控的数据先占住图表;
- 明确标记为 sample data;
- 等真实 statement line 出现后再替换。
所以你看到图表不等于系统已经有真实银行流水历史。
有时它只是 onboarding 期的占位视觉。
七、running balance 图为什么是“倒着推”的
_get_bank_cash_graph_data() 还有一个特别值得讲的点:
它拿到最近 30 天 statement line 的日汇总后,并不是从最早一天开始逐步累计到今天,而是:
- 先拿
current_statement_balance作为当前点; - 再按日期往前倒推,每天减去当天流水金额;
- 最后补足到一个月前。
这意味着图表的构造思路是:
从当前已知余额往历史回溯,而不是从历史初值往今天正向滚。
这样做的好处是:
- 当前余额一定和最新状态对齐;
- 即使中间只抓到最近一段流水,也能画出合理曲线;
- 不必重新求整段历史绝对起点。
所以这个图更像“最近趋势回溯图”,不是完整历史账本重演。
八、为什么 Dashboard 上 last statement 和 current balance 不是一回事
代码里同时有:
last_statement_idlast_balancecurrent_statement_balance
很多人会把它们混成一个数。
但它们语义并不相同:
last_statement_id / last_balance
更接近“最后一份 statement 文档的期末余额”。
current_statement_balance
更接近“当前 running balance 口径”。
而 Dashboard 上最终 account balance 又会再叠加 direct_payments_balance。
所以:
- statement ending balance
- current running balance
- dashboard account balance
其实是三种不同语义层。
把它们强行等同,就会不断觉得系统“算错了”。
九、最常见的 4 个误会
误会 1:Dashboard 就是总账余额
不是。它是操作视图。
误会 2:to check 就是未对账金额
不是。它是人工待检查队列。
误会 3:没有真实流水时图表也可信
不一定,可能只是 sample data。
误会 4:看到 outstanding / misc operations 就代表账错了
也不一定,它们只是提示资金动作还没走完整路径。
十、排查银行 Dashboard 数字“怪”的最好顺序
如果你遇到“Dashboard 数字对不上”,最实用的顺序通常是:
1)先分清你在比哪一种余额
- 总账余额
- statement ending balance
- current running balance
- dashboard account balance
2)看 to check 和 number_to_reconcile 是否被你混为一谈
这两个指标语义完全不同。
3)看 journal 是否有 direct payments 被并入口径
它们会抬高 dashboard balance。
4)看是否存在 misc operations
这些行不会自动等同于银行 statement 路径。
5)看图表是不是 sample data
新 journal 特别容易踩这个坑。
结论
Odoo 银行日记账 Dashboard 的核心设计,不是“显示一个银行账户余额”,而是把银行会计日常最关心的几类运营指标塞进一块卡片:
- 当前 running balance
- direct payments
- outstanding payments
- misc operations
- to check
- number to reconcile
- statement 历史趋势图
- 必要时的 sample data
所以它不是一张单口径财务报表,而是一张为银行对账和日常跟进服务的操作型 Dashboard。
只有先接受这一点,后面那些“为什么这个数和另一个数不一样”的问题,才会真正讲得通。
DISCUSSION
评论区